diff --git a/.dockerEnvExample b/.dockerEnvExample index 074404e..0d21628 100644 --- a/.dockerEnvExample +++ b/.dockerEnvExample @@ -1,4 +1,4 @@ OPENAI_API_KEY=sk-proj-... PB_SUPERUSER_EMAIL=8eQJuw2mXjpHdxVnhBKF@example.com PB_SUPERUSER_PASSWORD=8eQJuw2mXjpHdxVnhBKF -PB_VERSION=0.27.0 \ No newline at end of file +PB_VERSION=0.34.2 \ No newline at end of file diff --git a/.envExample b/.envExample index 9c83cdf..8c63f88 100644 --- a/.envExample +++ b/.envExample @@ -10,4 +10,4 @@ VITE_FUNCTIONS_URL=http://localhost:8081 VITE_POCKETBASE_URL=http://localhost:8080 # PocketBase (used in docker/staging) -PB_VERSION=0.27.0 \ No newline at end of file +PB_VERSION=0.34.2 \ No newline at end of file diff --git a/.gitignore b/.gitignore index ec915ae..4f7ea48 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ yarn-error.log* pnpm-debug.log* lerna-debug.log* -pocket_base node_modules dist dist-ssr @@ -17,6 +16,19 @@ dist-ssr .env .dockerEnv +# PocketBase runtime files +*.db +*.db-shm +*.db-wal +pocketbase/pocketbase +pocketbase/LICENSE.md +pocketbase/CHANGELOG.md +pocketbase/pb_data/storage/ + +# Old PocketBase directories (for migration period) +pb/ +pocket_base/ + # Editor directories and files .vscode/* !.vscode/extensions.json @@ -38,4 +50,8 @@ dist-ssr .yarn/cache .yarn/unplugged .yarn/build-state.yml -.yarn/install-state.gz \ No newline at end of file +.yarn/install-state.gz + +# AI +.cursor +.kiro \ No newline at end of file diff --git a/README.md b/README.md index d61ba1c..27174e3 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ Fullstack is a comprehensive full stack project template with React frontend, No git clone https://github.com/dastron/project.git cd project +# Rename the project from template (interactive) +yarn rename + # Install dependencies yarn install @@ -46,12 +49,20 @@ yarn build # Run PocketBase server only yarn pb +# Generate migrations from Zod schemas +yarn migrate:generate + +# Check migration status +yarn migrate:status + # Sync dev database migrations to/from project yarn pb:sync - # Creates a migration snapshot of the current pb yarn pb:snapshot + +# Create/regenerate base snapshot from PocketBase +yarn pb:base-snapshot ``` ### Testing & Quality @@ -78,17 +89,69 @@ yarn why # Check why a package is installed ``` project/ -├── app/ # Vite React frontend +├── app/ # Vite React frontend │ └── package.json -├── functions/ # Node.js/Express backend +├── functions/ # Node.js/Express backend │ └── package.json -├── shared/ # Shared code between workspaces +├── shared/ # Shared code between workspaces +│ ├── src/ +│ │ └── schema/ # Zod schemas (source of truth for DB) │ └── package.json -├── pb/ # PocketBase backend -├── package.json # Root configuration +├── pocketbase/ # PocketBase configuration +│ └── pb_migrations/ # Generated migration files +├── package.json # Root configuration └── README.md ``` +## Schema-Driven Migrations + +This project uses a schema-driven approach where Zod schemas in `shared/src/schema/` serve as the single source of truth for the database structure. Migrations are automatically generated from these schemas. + +### Base Snapshot + +The migration system uses a **base snapshot** (`pocketbase/pb_migrations/000000000_collections_snapshot.js`) that represents PocketBase's initial state with system collections. This file: + +- Contains PocketBase's default system collections (`_mfas`, `_otps`, `_externalAuths`, `_authOrigins`, `_superusers`) +- Includes the default `users` collection +- Serves as the starting point for schema comparisons +- Is automatically created during `yarn setup` if it doesn't exist + +**When to regenerate the base snapshot:** +- After upgrading PocketBase versions (system collections may change) +- When setting up a new development environment +- If the base snapshot is missing or corrupted + +```bash +yarn pb:base-snapshot +``` + +### Quick Start + +1. **Define schema** in `shared/src/schema/entity.ts`: +```typescript +import { z } from "zod"; +import { baseSchema } from "./base"; + +export const EntityInputSchema = z.object({ + name: z.string().min(2), + status: z.enum(["active", "inactive"]), +}); + +export const EntitySchema = EntityInputSchema.extend(baseSchema); +``` + +2. **Generate migration**: +```bash +yarn migrate:generate +``` + +3. **Apply migration** (automatic on PocketBase startup): +```bash +yarn pb +``` + +For complete documentation, see [shared/MIGRATION_GUIDE.md](./shared/MIGRATION_GUIDE.md). + ## Development Environment ### Prerequisites @@ -120,7 +183,7 @@ project/ VITE_POCKETBASE_URL='http://localhost:8080' # PocketBase URL for frontend # PocketBase (used in docker/staging) - PB_VERSION=0.27.0 # Specify desired PocketBase version + PB_VERSION=0.34.2 # Specify desired PocketBase version ``` 3. Adjust the configuration as needed for your environment. diff --git a/app/setupTests.ts b/app/setupTests.ts index 3191f29..b9a42a2 100644 --- a/app/setupTests.ts +++ b/app/setupTests.ts @@ -62,6 +62,13 @@ Object.keys(collectionsConfig).forEach((collectionName) => { >(collectionName); }); +const mockAuthStore = { + record: { + id: "123", + name: "Test User", + }, +}; + // Export the mock for use in your tests export const TypedPocketBaseMock = { ...vi.importActual("@/pb"), @@ -69,6 +76,7 @@ export const TypedPocketBaseMock = { return `https://picsum.photos/seed/${item.id}/1200/600`; }), filter: vi.fn(), + authStore: mockAuthStore, collection: vi.fn((name: string) => { const collection = mockTypedPocketBase[name]; if (!collection) { diff --git a/app/vitest.config.ts b/app/vitest.config.ts index 4c95257..5430f00 100644 --- a/app/vitest.config.ts +++ b/app/vitest.config.ts @@ -1,21 +1,18 @@ -import { mergeConfig } from "vite"; -import { defineConfig } from "vitest/config"; +import path from "path"; -import viteConfig from "./vite.config"; +import react from "@vitejs/plugin-react"; +import tsconfigPaths from "vite-tsconfig-paths"; +import { defineConfig } from "vitest/config"; -export default mergeConfig( - viteConfig, - defineConfig({ - test: { - environment: "happy-dom", - // globals: true, - // clearMocks: true, - // mockReset: true, - // restoreMocks: true, - setupFiles: ["setupTests.ts"], - alias: { - "@/": new URL("./src/", import.meta.url).pathname, - }, +export default defineConfig({ + plugins: [react(), tsconfigPaths()], + test: { + environment: "happy-dom", + setupFiles: ["setupTests.ts"], + }, + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), }, - }) -); + }, +}); diff --git a/config/supervisord.conf b/config/supervisord.conf index 55c03da..cdcb367 100644 --- a/config/supervisord.conf +++ b/config/supervisord.conf @@ -2,7 +2,7 @@ nodaemon=true [program:pocketbase] -command=/pb/pocketbase serve --http=0.0.0.0:8080 +command=/pocketbase/pocketbase serve --http=0.0.0.0:8080 stopsignal=SIGTERM stopasgroup=true killasgroup=true diff --git a/dev-setup.sh b/dev-setup.sh deleted file mode 100755 index 6f86f97..0000000 --- a/dev-setup.sh +++ /dev/null @@ -1,110 +0,0 @@ -#!/bin/bash - -# Default PocketBase version if not set in environment -DEFAULT_PB_VERSION="0.27.0" -PB_VERSION=${PB_VERSION:-$DEFAULT_PB_VERSION} -PB_PATH="./pocket_base" - -# Load superuser credentials from .env file if it exists -if [ -f ".env" ]; then - echo "Loading superuser credentials from .env file..." - # Simple approach to load just the two variables we need - export $(grep -E "^PB_SUPERUSER_EMAIL=" .env) - export $(grep -E "^PB_SUPERUSER_PASSWORD=" .env) -fi - -# Determine operating system -OS=$(uname -s) -case $OS in - Linux*) TARGETOS="linux" ;; - Darwin*) TARGETOS="darwin" ;; - CYGWIN*|MINGW*|MSYS*) TARGETOS="windows" ;; - *) echo "Unsupported operating system: $OS"; exit 1 ;; -esac - -# Determine architecture -ARCH=$(uname -m) -case $ARCH in - x86_64) TARGETARCH="amd64" ;; - arm64|aarch64) TARGETARCH="arm64" ;; - *) echo "Unsupported architecture: $ARCH"; exit 1 ;; -esac - -# Function to download and extract PocketBase -download_pocketbase() { - echo "Downloading PocketBase v${PB_VERSION} for ${TARGETOS} (${TARGETARCH})..." - mkdir -p "${PB_PATH}/tmp" - - # Use curl if wget is not available - if command -v wget >/dev/null 2>&1; then - wget -q "https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_${TARGETOS}_${TARGETARCH}.zip" -O "${PB_PATH}/tmp/pb.zip" - else - curl -sL "https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_${TARGETOS}_${TARGETARCH}.zip" -o "${PB_PATH}/tmp/pb.zip" - fi - - yes | unzip -o "${PB_PATH}/tmp/pb.zip" -d "${PB_PATH}/" - rm "${PB_PATH}/tmp/pb.zip" - echo "PocketBase v${PB_VERSION} installed successfully" -} - -# Create pocketbase directory if it doesn't exist -if [ ! -d "${PB_PATH}" ]; then - echo "Creating pocketbase directory..." - mkdir -p "${PB_PATH}" - download_pocketbase -else - # Check current version if pocketbase exists - if [ -f "${PB_PATH}/pocketbase" ]; then - CURRENT_VERSION=$("${PB_PATH}/pocketbase" --version 2>&1 | sed 's/^.*version //' | sed 's/^v//') - if [ "$CURRENT_VERSION" != "$PB_VERSION" ]; then - echo "Updating PocketBase from v${CURRENT_VERSION} to v${PB_VERSION}..." - rm -rf "${PB_PATH}/pocketbase" - download_pocketbase - else - echo "PocketBase is already at version ${PB_VERSION}" - fi - else - echo "PocketBase executable not found, downloading..." - download_pocketbase - fi -fi - -# Copy migrations and data if they exist -if [ -d "./pb/pb_migrations" ]; then - echo "Copying migrations..." - mkdir -p "${PB_PATH}/pb_migrations" - cp -R ./pb/pb_migrations/* "${PB_PATH}/pb_migrations/" -fi - -if [ -d "./pb/pb_data" ]; then - echo "Copying data..." - mkdir -p "${PB_PATH}/pb_data" - cp -R ./pb/pb_data/* "${PB_PATH}/pb_data/" -fi - -# Check if superuser credentials are provided and valid -if [ -n "$PB_SUPERUSER_EMAIL" ] && [ -n "$PB_SUPERUSER_PASSWORD" ]; then - echo "Superuser credentials provided. Validating..." - # Basic email format validation - if echo "$PB_SUPERUSER_EMAIL" | grep -qE '^[^ ]+@[^ ]+\.[^ ]+$'; then - # Password length validation - if [ ${#PB_SUPERUSER_PASSWORD} -ge 10 ]; then - echo "Credentials valid. Attempting to create superuser..." - "${PB_PATH}/pocketbase" superuser upsert "$PB_SUPERUSER_EMAIL" "$PB_SUPERUSER_PASSWORD" - # Check the exit status of the command - if [ $? -eq 0 ]; then - echo "Superuser created successfully or already exists." - else - echo "Failed to create superuser. Check PocketBase logs for details." - fi - else - echo "Password validation failed: Password must be at least 10 characters long." - fi - else - echo "Email validation failed: Invalid email format." - fi -else - echo "Superuser credentials not provided or incomplete. Skipping superuser creation." -fi - -echo "Setup complete!" diff --git a/dockerfile b/dockerfile index bd20f8d..3853f77 100644 --- a/dockerfile +++ b/dockerfile @@ -41,18 +41,18 @@ RUN yarn build ################################################### FROM alpine:latest AS pocketbase -ARG PB_VERSION=0.27.0 +ARG PB_VERSION=0.34.2 ARG TARGETARCH ENV ACTUAL_PB_VERSION=${PB_VERSION} RUN apk add --no-cache unzip ca-certificates wget \ && wget -q https://github.com/pocketbase/pocketbase/releases/download/v${ACTUAL_PB_VERSION}/pocketbase_${ACTUAL_PB_VERSION}_linux_${TARGETARCH}.zip -O /tmp/pb.zip \ - && unzip /tmp/pb.zip -d /pb/ \ + && unzip /tmp/pb.zip -d /pocketbase/ \ && rm /tmp/pb.zip -COPY pb/pb_migrations /pb/pb_migrations -COPY pb/pb_data /pb/pb_data -COPY pb/pb_hooks /pb/pb_hooks +COPY pocketbase/pb_migrations /pocketbase/pb_migrations +COPY pocketbase/pb_data /pocketbase/pb_data +COPY pocketbase/pb_hooks /pocketbase/pb_hooks ################################################### @@ -73,7 +73,7 @@ RUN apk add --no-cache --update nginx supervisor bash # RUN corepack enable && corepack prepare yarn@4.7.0 --activate # 1) Copy PocketBase from its build stage -COPY --from=pocketbase /pb /pb +COPY --from=pocketbase /pocketbase /pocketbase # 2) Set up project workspace WORKDIR /workspace @@ -99,7 +99,7 @@ COPY --from=builder /repo/app/dist /usr/share/nginx/html # 6) Nginx & Supervisor config and entrypoint COPY config/nginx.conf /etc/nginx/nginx.conf COPY config/supervisord.conf /etc/supervisord.conf -COPY entrypoint.sh /usr/local/bin/ +COPY scripts/entrypoint.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/entrypoint.sh EXPOSE 80 8080 8081 diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100644 index 2e988f4..0000000 --- a/entrypoint.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/sh - -# Display version information if available -if [ -n "$VERSION" ]; then - echo "Starting application version: $VERSION" -fi - -check_files() { - if [ -f "/pb/pb_data/auxiliary.db-shm" ] || \ - [ -f "/pb/pb_data/auxiliary.db-wal" ] || \ - [ -f "/pb/pb_data/data.db-shm" ] || \ - [ -f "/pb/pb_data/data.db-wal" ]; then - return 0 # Files exist, keep waiting - else - return 1 # Files don't exist, safe to proceed - fi -} - -TIMEOUT=3 -INTERVAL=1 -MAX_ATTEMPTS=$((TIMEOUT / INTERVAL)) - -ATTEMPT=1 -while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do - if ! check_files; then - echo "All lock files are gone." - break - else - echo "Lock files present, waiting $INTERVAL seconds (attempt $ATTEMPT/$MAX_ATTEMPTS)..." - sleep $INTERVAL - ATTEMPT=$((ATTEMPT + 1)) - fi -done - -if [ $ATTEMPT -gt $MAX_ATTEMPTS ]; then - echo "Timeout reached after $TIMEOUT seconds. Lock files still present. Starting server anyway." -else - echo "Starting server..." -fi - -# Check if superuser credentials are provided and valid -if [ -n "$PB_SUPERUSER_EMAIL" ] && [ -n "$PB_SUPERUSER_PASSWORD" ]; then - echo "Superuser credentials provided. Validating..." - # Basic email format validation - if echo "$PB_SUPERUSER_EMAIL" | grep -qE '^[^ ]+@[^ ]+\.[^ ]+$'; then - # Password length validation - if [ ${#PB_SUPERUSER_PASSWORD} -ge 10 ]; then - echo "Credentials valid. Attempting to create superuser..." - /pb/pocketbase superuser upsert "$PB_SUPERUSER_EMAIL" "$PB_SUPERUSER_PASSWORD" - # Check the exit status of the command - if [ $? -eq 0 ]; then - echo "Superuser created successfully or already exists." - else - echo "Failed to create superuser. Check PocketBase logs for details." - fi - else - echo "Password validation failed: Password must be at least 10 characters long." - fi - else - echo "Email validation failed: Invalid email format." - fi -else - echo "Superuser credentials not provided or incomplete. Skipping superuser creation." -fi - -exec "$@" diff --git a/package.json b/package.json index c9bce73..da13c8d 100644 --- a/package.json +++ b/package.json @@ -8,17 +8,20 @@ ], "scripts": { "setup": "yarn install && yarn run setup:script && yarn run setup:install && yarn run setup:build", - "setup:script": "chmod +x ./dev-setup.sh && ./dev-setup.sh", + "setup:script": "chmod +x ./scripts/dev-setup.sh && ./scripts/dev-setup.sh", "setup:install": "yarn install", "setup:build": "yarn build", "build": "yarn workspaces foreach --all --topological run build", - "pb": "./pocket_base/pocketbase serve --http=\"0.0.0.0:8080\" --hooksDir ./pb/pb_hooks", + "pb": "./pocketbase/pocketbase serve --http=\"0.0.0.0:8080\"", "pb:sync": "yarn pb:migrate", - "pb:migrate": "chmod +x ./pb-migrate.sh && ./pb-migrate.sh", - "pb:snapshot": "echo 'y' | ./pocket_base/pocketbase migrate collections", - "dev": "concurrently \"yarn workspace @project/shared dev\" \"yarn workspace @project/app dev\" \"yarn workspace @project/functions dev\" \"./pocket_base/pocketbase serve --http=\\\"0.0.0.0:8080\\\" --hooksDir ./pb/pb_hooks\"", + "pb:migrate": "chmod +x ./scripts/pb-migrate.sh && ./scripts/pb-migrate.sh", + "pb:snapshot": "echo 'y' | ./pocketbase/pocketbase migrate collections", + "migrate:generate": "yarn workspace @project/shared migrate:generate", + "migrate:status": "yarn workspace @project/shared migrate:status", + "migrate:verify": "chmod +x ./scripts/verify-schema-sync.sh && ./scripts/verify-schema-sync.sh", + "dev": "concurrently \"yarn workspace @project/shared dev\" \"yarn workspace @project/app dev\" \"yarn workspace @project/functions dev\" \"./pocketbase/pocketbase serve --http=\\\"0.0.0.0:8080\\\"\"", "staging": "echo 'building...' && docker run --rm -it --env-file \".dockerEnv\" -p 7081:8081 -p 7001:80 -p 7080:8080 $(docker build -q .)", - "check": "yarn format && yarn lint && yarn typecheck", + "check": "yarn format && yarn lint && yarn typecheck && yarn migrate:verify", "format": "yarn workspaces foreach --all run format", "lint": "yarn workspaces foreach --all run lint", "typecheck": "yarn workspaces foreach --all run typecheck", @@ -27,6 +30,7 @@ "test:all": "yarn workspaces foreach --all run test", "outdated": "yarn workspaces foreach -pR run npm outdated", "focus": "yarn workspaces focus", + "rename": "node ./scripts/rename-project.js", "why": "yarn why" }, "author": "dastron ", diff --git a/pb-migrate.sh b/pb-migrate.sh deleted file mode 100755 index 1916f70..0000000 --- a/pb-migrate.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh -set -e # Exit immediately if a command exits with a non-zero status - -PB_PATH="./pocket_base" -PB_MIGRATIONS="${PB_PATH}/pb_migrations" -APP_MIGRATIONS="./pb/pb_migrations" - -echo "Starting PocketBase migration process..." - -# Ensure migration directories exist -mkdir -p "${PB_MIGRATIONS}" -mkdir -p "${APP_MIGRATIONS}" - -# Sync migrations between both folders (bidirectional sync) -echo "Syncing migration files..." - -# Copy from app migrations to PocketBase migrations -if [ -d "${APP_MIGRATIONS}" ] && [ "$(ls -A ${APP_MIGRATIONS} 2>/dev/null)" ]; then - echo "Copying app migrations to PocketBase..." - cp -R "${APP_MIGRATIONS}/"* "${PB_MIGRATIONS}/" -fi - -# Copy from PocketBase migrations to app migrations -if [ -d "${PB_MIGRATIONS}" ] && [ "$(ls -A ${PB_MIGRATIONS} 2>/dev/null)" ]; then - echo "Copying PocketBase migrations to app..." - cp -R "${PB_MIGRATIONS}/"* "${APP_MIGRATIONS}/" -fi - -# Run migrations -echo "Running migrations..." -"${PB_PATH}/pocketbase" migrate up - -echo "Migration completed successfully!" \ No newline at end of file diff --git a/pb/README.md b/pb/README.md deleted file mode 100644 index 3961c33..0000000 --- a/pb/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# PocketBase Production Data - -This folder contains production PocketBase data that will be deployed with the application. - -## Purpose - -- **Production Data Only**: Files in this directory are intended for production use and will be included in deployments. -- **Version Controlled**: This directory is tracked in the repository, so any data stored here will be saved in version control. - -## Development vs. Production - -- For development purposes, use the `../pocket_base` directory instead, which is excluded from the repository. -- Development data in `../pocket_base` will not be committed to version control or deployed. - -## Usage - -- Place migrations, schema definitions, and initial data that should be available in production. -- Avoid storing sensitive data or large binary files in this directory. -- Use the command `yarn pb:sync` to synchronize changes between development and production environments when needed. -- Use `yarn pb:snapshot` to create a migration snapshot of the current PocketBase configuration. - -## Deployment Notes - -When deploying the application, PocketBase will use the data and migrations from this directory to initialize or update the database structure. diff --git a/pb/pb_data/types.d.ts b/pocketbase/pb_data/types.d.ts similarity index 59% rename from pb/pb_data/types.d.ts rename to pocketbase/pb_data/types.d.ts index 0ee8fd7..7802c8e 100644 --- a/pb/pb_data/types.d.ts +++ b/pocketbase/pb_data/types.d.ts @@ -1,4 +1,4 @@ -// 1730628021 +// 1763801943 // GENERATED CODE - DO NOT MODIFY BY HAND // ------------------------------------------------------------------- @@ -55,9 +55,9 @@ declare function cronRemove(jobId: string): void; * Example: * * ```js - * routerAdd("GET", "/hello", (c) => { - * return c.json(200, {"message": "Hello!"}) - * }, $apis.requireAdminOrRecordAuth()) + * routerAdd("GET", "/hello", (e) => { + * return e.json(200, {"message": "Hello!"}) + * }, $apis.requireAuth()) * ``` * * _Note that this method is available only in pb_hooks context._ @@ -67,8 +67,8 @@ declare function cronRemove(jobId: string): void; declare function routerAdd( method: string, path: string, - handler: echo.HandlerFunc, - ...middlewares: Array, + handler: (e: core.RequestEvent) => void, + ...middlewares: Array void)|Middleware>, ): void; /** @@ -78,11 +78,9 @@ declare function routerAdd( * Example: * * ```js - * routerUse((next) => { - * return (c) => { - * console.log(c.path()) - * return next(c) - * } + * routerUse((e) => { + * console.log(e.request.url.path) + * return e.next() * }) * ``` * @@ -90,34 +88,7 @@ declare function routerAdd( * * @group PocketBase */ -declare function routerUse(...middlewares: Array): void; - -/** - * RouterPre registers one or more global middlewares that are executed - * BEFORE the router processes the request. It is usually used for making - * changes to the request properties, for example, adding or removing - * a trailing slash or adding segments to a path so it matches a route. - * - * NB! Since the router will not have processed the request yet, - * middlewares registered at this level won't have access to any path - * related APIs from echo.Context. - * - * Example: - * - * ```js - * routerPre((next) => { - * return (c) => { - * console.log(c.request().url) - * return next(c) - * } - * }) - * ``` - * - * _Note that this method is available only in pb_hooks context._ - * - * @group PocketBase - */ -declare function routerPre(...middlewares: Array): void; +declare function routerUse(...middlewares: Array void)|Middleware>): void; // ------------------------------------------------------------------- // baseBinds @@ -135,7 +106,7 @@ declare var __hooks: string // // See https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#key-remapping-via-as type excludeHooks = { - [Property in keyof Type as Exclude]: Type[Property] + [Property in keyof Type as Exclude]: Type[Property] }; // CoreApp without the on* hook methods @@ -170,8 +141,6 @@ declare var $app: PocketBase * ).render({"name": "John"}) * ``` * - * _Note that this method is available only in pb_hooks context._ - * * @namespace * @group PocketBase */ @@ -199,14 +168,46 @@ declare function readerToString(reader: any, maxBytes?: number): string; * // io.Reader * const ex1 = toString(e.request.body) * - * // slice of bytes ("hello") - * const ex2 = toString([104 101 108 108 111]) + * // slice of bytes + * const ex2 = toString([104 101 108 108 111]) // "hello" + * + * // null + * const ex3 = toString(null) // "" * ``` * * @group PocketBase */ declare function toString(val: any, maxBytes?: number): string; +/** + * toBytes converts the specified value into a bytes slice. + * + * Support optional second maxBytes argument to limit the max read bytes + * when the value is a io.Reader (default to 32MB). + * + * Types that don't have Go slice representation (bool, objects, etc.) + * are serialized to UTF8 string and its bytes slice is returned. + * + * Example: + * + * ```js + * // io.Reader + * const ex1 = toBytes(e.request.body) + * + * // string + * const ex2 = toBytes("hello") // [104 101 108 108 111] + * + * // object (the same as the string '{"test":1}') + * const ex3 = toBytes({"test":1}) // [123 34 116 101 115 116 34 58 49 125] + * + * // null + * const ex4 = toBytes(null) // [] + * ``` + * + * @group PocketBase + */ +declare function toBytes(val: any, maxBytes?: number): Array; + /** * sleep pauses the current goroutine for at least the specified user duration (in ms). * A zero or negative duration returns immediately. @@ -230,7 +231,7 @@ declare function sleep(milliseconds: number): void; * ```js * const records = arrayOf(new Record) * - * $app.dao().recordQuery("articles").limit(10).all(records) + * $app.recordQuery("articles").limit(10).all(records) * ``` * * @group PocketBase @@ -240,15 +241,20 @@ declare function arrayOf(model: T): Array; /** * DynamicModel creates a new dynamic model with fields from the provided data shape. * + * Caveats: + * - In order to use 0 as double/float initialization number you have to negate it (`-0`). + * - You need to use lowerCamelCase when accessing the model fields (e.g. `model.roles` and not `model.Roles`). + * * Example: * * ```js * const model = new DynamicModel({ - * name: "" - * age: 0, - * active: false, - * roles: [], - * meta: {} + * name: "" + * age: 0, // int64 + * totalSpent: -0, // float64 + * active: false, + * Roles: [], // maps to "Roles" in the DB/JSON but the prop would be accessible via "model.roles" + * meta: {} * }) * ``` * @@ -258,11 +264,38 @@ declare class DynamicModel { constructor(shape?: { [key:string]: any }) } +interface Context extends context.Context{} // merge +/** + * Context creates a new empty Go context.Context. + * + * This is usually used as part of some Go transitive bindings. + * + * Example: + * + * ```js + * const blank = new Context() + * + * // with single key-value pair + * const base = new Context(null, "a", 123) + * console.log(base.value("a")) // 123 + * + * // extend with additional key-value pair + * const sub = new Context(base, "b", 456) + * console.log(sub.value("a")) // 123 + * console.log(sub.value("b")) // 456 + * ``` + * + * @group PocketBase + */ +declare class Context implements context.Context { + constructor(parentCtx?: Context, key?: any, value?: any) +} + /** * Record model class. * * ```js - * const collection = $app.dao().findCollectionByNameOrId("article") + * const collection = $app.findCollectionByNameOrId("article") * * const record = new Record(collection, { * title: "Lorem ipsum" @@ -275,28 +308,31 @@ declare class DynamicModel { * @group PocketBase */ declare const Record: { - new(collection?: models.Collection, data?: { [key:string]: any }): models.Record + new(collection?: core.Collection, data?: { [key:string]: any }): core.Record // note: declare as "newable" const due to conflict with the Record TS utility type } -interface Collection extends models.Collection{} // merge +interface Collection extends core.Collection{ + type: "base" | "view" | "auth" +} // merge /** * Collection model class. * * ```js * const collection = new Collection({ - * name: "article", * type: "base", + * name: "article", * listRule: "@request.auth.id != '' || status = 'public'", * viewRule: "@request.auth.id != '' || status = 'public'", * deleteRule: "@request.auth.id != ''", - * schema: [ + * fields: [ * { * name: "title", * type: "text", * required: true, - * options: { min: 6, max: 100 }, + * min: 6, + * max: 100, * }, * { * name: "description", @@ -308,44 +344,168 @@ interface Collection extends models.Collection{} // merge * * @group PocketBase */ -declare class Collection implements models.Collection { - constructor(data?: Partial) +declare class Collection implements core.Collection { + constructor(data?: Partial) } -interface Admin extends models.Admin{} // merge +interface FieldsList extends core.FieldsList{} // merge /** - * Admin model class. + * FieldsList model class, usually used to define the Collection.fields. * - * ```js - * const admin = new Admin() - * admin.email = "test@example.com" - * admin.setPassword(1234567890) - * ``` + * @group PocketBase + */ +declare class FieldsList implements core.FieldsList { + constructor(data?: Partial) +} + +interface Field extends core.Field{} // merge +/** + * Field model class, usually used as part of the FieldsList model. + * + * @group PocketBase + */ +declare class Field implements core.Field { + constructor(data?: Partial) +} + +interface NumberField extends core.NumberField{} // merge +/** + * {@inheritDoc core.NumberField} + * + * @group PocketBase + */ +declare class NumberField implements core.NumberField { + constructor(data?: Partial) +} + +interface BoolField extends core.BoolField{} // merge +/** + * {@inheritDoc core.BoolField} + * + * @group PocketBase + */ +declare class BoolField implements core.BoolField { + constructor(data?: Partial) +} + +interface TextField extends core.TextField{} // merge +/** + * {@inheritDoc core.TextField} + * + * @group PocketBase + */ +declare class TextField implements core.TextField { + constructor(data?: Partial) +} + +interface URLField extends core.URLField{} // merge +/** + * {@inheritDoc core.URLField} + * + * @group PocketBase + */ +declare class URLField implements core.URLField { + constructor(data?: Partial) +} + +interface EmailField extends core.EmailField{} // merge +/** + * {@inheritDoc core.EmailField} + * + * @group PocketBase + */ +declare class EmailField implements core.EmailField { + constructor(data?: Partial) +} + +interface EditorField extends core.EditorField{} // merge +/** + * {@inheritDoc core.EditorField} + * + * @group PocketBase + */ +declare class EditorField implements core.EditorField { + constructor(data?: Partial) +} + +interface PasswordField extends core.PasswordField{} // merge +/** + * {@inheritDoc core.PasswordField} + * + * @group PocketBase + */ +declare class PasswordField implements core.PasswordField { + constructor(data?: Partial) +} + +interface DateField extends core.DateField{} // merge +/** + * {@inheritDoc core.DateField} + * + * @group PocketBase + */ +declare class DateField implements core.DateField { + constructor(data?: Partial) +} + +interface AutodateField extends core.AutodateField{} // merge +/** + * {@inheritDoc core.AutodateField} + * + * @group PocketBase + */ +declare class AutodateField implements core.AutodateField { + constructor(data?: Partial) +} + +interface JSONField extends core.JSONField{} // merge +/** + * {@inheritDoc core.JSONField} + * + * @group PocketBase + */ +declare class JSONField implements core.JSONField { + constructor(data?: Partial) +} + +interface RelationField extends core.RelationField{} // merge +/** + * {@inheritDoc core.RelationField} + * + * @group PocketBase + */ +declare class RelationField implements core.RelationField { + constructor(data?: Partial) +} + +interface SelectField extends core.SelectField{} // merge +/** + * {@inheritDoc core.SelectField} * * @group PocketBase */ -declare class Admin implements models.Admin { - constructor(data?: Partial) +declare class SelectField implements core.SelectField { + constructor(data?: Partial) } -interface Schema extends schema.Schema{} // merge +interface FileField extends core.FileField{} // merge /** - * Schema model class, usually used to define the Collection.schema field. + * {@inheritDoc core.FileField} * * @group PocketBase */ -declare class Schema implements schema.Schema { - constructor(data?: Partial) +declare class FileField implements core.FileField { + constructor(data?: Partial) } -interface SchemaField extends schema.SchemaField{} // merge +interface GeoPointField extends core.GeoPointField{} // merge /** - * SchemaField model class, usually used as part of the Schema model. + * {@inheritDoc core.GeoPointField} * * @group PocketBase */ -declare class SchemaField implements schema.SchemaField { - constructor(data?: Partial) +declare class GeoPointField implements core.GeoPointField { + constructor(data?: Partial) } interface MailerMessage extends mailer.Message{} // merge @@ -393,49 +553,108 @@ declare class Command implements cobra.Command { constructor(cmd?: Partial) } -interface RequestInfo extends models.RequestInfo{} // merge /** - * RequestInfo defines a single models.RequestInfo instance, usually used + * RequestInfo defines a single core.RequestInfo instance, usually used * as part of various filter checks. * * Example: * * ```js - * const authRecord = $app.dao().findAuthRecordByEmail("users", "test@example.com") + * const authRecord = $app.findAuthRecordByEmail("users", "test@example.com") * * const info = new RequestInfo({ - * authRecord: authRecord, - * data: {"name": 123}, - * headers: {"x-token": "..."}, + * auth: authRecord, + * body: {"name": 123}, + * headers: {"x-token": "..."}, * }) * - * const record = $app.dao().findFirstRecordByData("articles", "slug", "hello") + * const record = $app.findFirstRecordByData("articles", "slug", "hello") + * + * const canAccess = $app.canAccessRecord(record, info, "@request.auth.id != '' && @request.body.name = 123") + * ``` + * + * @group PocketBase + */ +declare const RequestInfo: { + new(info?: Partial): core.RequestInfo + + // note: declare as "newable" const due to conflict with the RequestInfo TS node type +} + +/** + * Middleware defines a single request middleware handler. + * + * This class is usually used when you want to explicitly specify a priority to your custom route middleware. + * + * Example: + * + * ```js + * routerUse(new Middleware((e) => { + * console.log(e.request.url.path) + * return e.next() + * }, -10)) + * ``` + * + * @group PocketBase + */ +declare class Middleware { + constructor( + func: string|((e: core.RequestEvent) => void), + priority?: number, + id?: string, + ) +} + +interface Timezone extends time.Location{} // merge +/** + * Timezone returns the timezone location with the given name. * - * const canAccess = $app.dao().canAccessRecord(record, info, "@request.auth.id != '' && @request.data.name = 123") + * The name is expected to be a location name corresponding to a file + * in the IANA Time Zone database, such as "America/New_York". + * + * If the name is "Local", LoadLocation returns Local. + * + * If the name is "", invalid or "UTC", returns UTC. + * + * The constructor is equivalent to calling the Go `time.LoadLocation(name)` method. + * + * Example: + * + * ```js + * const zone = new Timezone("America/New_York") + * $app.cron().setTimezone(zone) * ``` * * @group PocketBase */ -declare class RequestInfo implements models.RequestInfo { - constructor(date?: Partial) +declare class Timezone implements time.Location { + constructor(name?: string) } interface DateTime extends types.DateTime{} // merge /** * DateTime defines a single DateTime type instance. + * The returned date is always represented in UTC. * * Example: * * ```js * const dt0 = new DateTime() // now * + * // full datetime string * const dt1 = new DateTime('2023-07-01 00:00:00.000Z') + * + * // datetime string with default "parse in" timezone location + * // + * // similar to new DateTime('2023-07-01 00:00:00 +01:00') or new DateTime('2023-07-01 00:00:00 +02:00') + * // but accounts for the daylight saving time (DST) + * const dt2 = new DateTime('2023-07-01 00:00:00', 'Europe/Amsterdam') * ``` * * @group PocketBase */ declare class DateTime implements types.DateTime { - constructor(date?: string) + constructor(date?: string, defaultParseInLocation?: string) } interface ValidationError extends ozzo_validation.Error{} // merge @@ -453,15 +672,6 @@ declare class ValidationError implements ozzo_validation.Error { constructor(code?: string, message?: string) } -interface Dao extends daos.Dao{} // merge -/** - * @inheritDoc - * @group PocketBase - */ -declare class Dao implements daos.Dao { - constructor(concurrentDB?: dbx.Builder, nonconcurrentDB?: dbx.Builder) -} - interface Cookie extends http.Cookie{} // merge /** * A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an @@ -547,44 +757,22 @@ declare namespace $dbx { export let notBetween: dbx.notBetween } -// ------------------------------------------------------------------- -// tokensBinds -// ------------------------------------------------------------------- - -/** - * `$tokens` defines high level helpers to generate - * various admins and auth records tokens (auth, forgotten password, etc.). - * - * For more control over the generated token, you can check `$security`. - * - * @group PocketBase - */ -declare namespace $tokens { - let adminAuthToken: tokens.newAdminAuthToken - let adminResetPasswordToken: tokens.newAdminResetPasswordToken - let adminFileToken: tokens.newAdminFileToken - let recordAuthToken: tokens.newRecordAuthToken - let recordVerifyToken: tokens.newRecordVerifyToken - let recordResetPasswordToken: tokens.newRecordResetPasswordToken - let recordChangeEmailToken: tokens.newRecordChangeEmailToken - let recordFileToken: tokens.newRecordFileToken -} - // ------------------------------------------------------------------- // mailsBinds // ------------------------------------------------------------------- /** * `$mails` defines helpers to send common - * admins and auth records emails like verification, password reset, etc. + * auth records emails like verification, password reset, etc. * * @group PocketBase */ declare namespace $mails { - let sendAdminPasswordReset: mails.sendAdminPasswordReset let sendRecordPasswordReset: mails.sendRecordPasswordReset let sendRecordVerification: mails.sendRecordVerification let sendRecordChangeEmail: mails.sendRecordChangeEmail + let sendRecordOTP: mails.sendRecordOTP + let sendRecordAuthAlert: mails.sendRecordAuthAlert } // ------------------------------------------------------------------- @@ -600,6 +788,7 @@ declare namespace $mails { declare namespace $security { let randomString: security.randomString let randomStringWithAlphabet: security.randomStringWithAlphabet + let randomStringByRegex: security.randomStringByRegex let pseudorandomString: security.pseudorandomString let pseudorandomStringWithAlphabet: security.pseudorandomStringWithAlphabet let encrypt: security.encrypt @@ -610,7 +799,11 @@ declare namespace $security { let md5: security.md5 let sha256: security.sha256 let sha512: security.sha512 - let createJWT: security.newJWT + + /** + * {@inheritDoc security.newJWT} + */ + export function createJWT(payload: { [key:string]: any }, signingKey: string, secDuration: number): string /** * {@inheritDoc security.parseUnverifiedJWT} @@ -639,20 +832,20 @@ declare namespace $filesystem { let fileFromMultipart: filesystem.newFileFromMultipart /** - * fileFromUrl creates a new File from the provided url by + * fileFromURL creates a new File from the provided url by * downloading the resource and creating a BytesReader. * * Example: * * ```js * // with default max timeout of 120sec - * const file1 = $filesystem.fileFromUrl("https://...") + * const file1 = $filesystem.fileFromURL("https://...") * * // with custom timeout of 15sec - * const file2 = $filesystem.fileFromUrl("https://...", 15) + * const file2 = $filesystem.fileFromURL("https://...", 15) * ``` */ - export function fileFromUrl(url: string, secTimeout?: number): filesystem.File + export function fileFromURL(url: string, secTimeout?: number): filesystem.File } // ------------------------------------------------------------------- @@ -714,301 +907,194 @@ declare namespace $os { */ export let cmd: exec.command - export let args: os.args - export let exit: os.exit - export let getenv: os.getenv - export let dirFS: os.dirFS - export let readFile: os.readFile - export let writeFile: os.writeFile - export let readDir: os.readDir - export let tempDir: os.tempDir - export let truncate: os.truncate - export let getwd: os.getwd - export let mkdir: os.mkdir - export let mkdirAll: os.mkdirAll - export let rename: os.rename - export let remove: os.remove - export let removeAll: os.removeAll + /** + * Args hold the command-line arguments, starting with the program name. + */ + export let args: Array + + export let exit: os.exit + export let getenv: os.getenv + export let dirFS: os.dirFS + export let readFile: os.readFile + export let writeFile: os.writeFile + export let stat: os.stat + export let readDir: os.readDir + export let tempDir: os.tempDir + export let truncate: os.truncate + export let getwd: os.getwd + export let mkdir: os.mkdir + export let mkdirAll: os.mkdirAll + export let rename: os.rename + export let remove: os.remove + export let removeAll: os.removeAll + export let openRoot: os.openRoot + export let openInRoot: os.openInRoot } // ------------------------------------------------------------------- // formsBinds // ------------------------------------------------------------------- -interface AdminLoginForm extends forms.AdminLogin{} // merge +interface AppleClientSecretCreateForm extends forms.AppleClientSecretCreate{} // merge /** * @inheritDoc * @group PocketBase */ -declare class AdminLoginForm implements forms.AdminLogin { +declare class AppleClientSecretCreateForm implements forms.AppleClientSecretCreate { constructor(app: CoreApp) } -interface AdminPasswordResetConfirmForm extends forms.AdminPasswordResetConfirm{} // merge +interface RecordUpsertForm extends forms.RecordUpsert{} // merge /** * @inheritDoc * @group PocketBase */ -declare class AdminPasswordResetConfirmForm implements forms.AdminPasswordResetConfirm { - constructor(app: CoreApp) +declare class RecordUpsertForm implements forms.RecordUpsert { + constructor(app: CoreApp, record: core.Record) } -interface AdminPasswordResetRequestForm extends forms.AdminPasswordResetRequest{} // merge +interface TestEmailSendForm extends forms.TestEmailSend{} // merge /** * @inheritDoc * @group PocketBase */ -declare class AdminPasswordResetRequestForm implements forms.AdminPasswordResetRequest { +declare class TestEmailSendForm implements forms.TestEmailSend { constructor(app: CoreApp) } -interface AdminUpsertForm extends forms.AdminUpsert{} // merge +interface TestS3FilesystemForm extends forms.TestS3Filesystem{} // merge /** * @inheritDoc * @group PocketBase */ -declare class AdminUpsertForm implements forms.AdminUpsert { - constructor(app: CoreApp, admin: models.Admin) +declare class TestS3FilesystemForm implements forms.TestS3Filesystem { + constructor(app: CoreApp) } -interface AppleClientSecretCreateForm extends forms.AppleClientSecretCreate{} // merge +// ------------------------------------------------------------------- +// apisBinds +// ------------------------------------------------------------------- + +interface ApiError extends router.ApiError{} // merge /** * @inheritDoc + * * @group PocketBase */ -declare class AppleClientSecretCreateForm implements forms.AppleClientSecretCreate { - constructor(app: CoreApp) +declare class ApiError implements router.ApiError { + constructor(status?: number, message?: string, data?: any) } -interface CollectionUpsertForm extends forms.CollectionUpsert{} // merge +interface NotFoundError extends router.ApiError{} // merge /** - * @inheritDoc + * NotFounderor returns 404 ApiError. + * * @group PocketBase */ -declare class CollectionUpsertForm implements forms.CollectionUpsert { - constructor(app: CoreApp, collection: models.Collection) +declare class NotFoundError implements router.ApiError { + constructor(message?: string, data?: any) } -interface CollectionsImportForm extends forms.CollectionsImport{} // merge +interface BadRequestError extends router.ApiError{} // merge /** - * @inheritDoc + * BadRequestError returns 400 ApiError. + * * @group PocketBase */ -declare class CollectionsImportForm implements forms.CollectionsImport { - constructor(app: CoreApp) +declare class BadRequestError implements router.ApiError { + constructor(message?: string, data?: any) } -interface RealtimeSubscribeForm extends forms.RealtimeSubscribe{} // merge +interface ForbiddenError extends router.ApiError{} // merge /** - * @inheritDoc + * ForbiddenError returns 403 ApiError. + * * @group PocketBase */ -declare class RealtimeSubscribeForm implements forms.RealtimeSubscribe {} +declare class ForbiddenError implements router.ApiError { + constructor(message?: string, data?: any) +} -interface RecordEmailChangeConfirmForm extends forms.RecordEmailChangeConfirm{} // merge +interface UnauthorizedError extends router.ApiError{} // merge /** - * @inheritDoc + * UnauthorizedError returns 401 ApiError. + * * @group PocketBase */ -declare class RecordEmailChangeConfirmForm implements forms.RecordEmailChangeConfirm { - constructor(app: CoreApp, collection: models.Collection) +declare class UnauthorizedError implements router.ApiError { + constructor(message?: string, data?: any) } -interface RecordEmailChangeRequestForm extends forms.RecordEmailChangeRequest{} // merge +interface TooManyRequestsError extends router.ApiError{} // merge /** - * @inheritDoc + * TooManyRequestsError returns 429 ApiError. + * * @group PocketBase */ -declare class RecordEmailChangeRequestForm implements forms.RecordEmailChangeRequest { - constructor(app: CoreApp, record: models.Record) +declare class TooManyRequestsError implements router.ApiError { + constructor(message?: string, data?: any) } -interface RecordOAuth2LoginForm extends forms.RecordOAuth2Login{} // merge +interface InternalServerError extends router.ApiError{} // merge /** - * @inheritDoc + * InternalServerError returns 429 ApiError. + * * @group PocketBase */ -declare class RecordOAuth2LoginForm implements forms.RecordOAuth2Login { - constructor(app: CoreApp, collection: models.Collection, optAuthRecord?: models.Record) +declare class InternalServerError implements router.ApiError { + constructor(message?: string, data?: any) } -interface RecordPasswordLoginForm extends forms.RecordPasswordLogin{} // merge /** - * @inheritDoc + * `$apis` defines commonly used PocketBase api helpers and middlewares. + * * @group PocketBase */ -declare class RecordPasswordLoginForm implements forms.RecordPasswordLogin { - constructor(app: CoreApp, collection: models.Collection) +declare namespace $apis { + /** + * Route handler to serve static directory content (html, js, css, etc.). + * + * If a file resource is missing and indexFallback is set, the request + * will be forwarded to the base index.html (useful for SPA). + */ + export function static(dir: string, indexFallback: boolean): (e: core.RequestEvent) => void + + let requireGuestOnly: apis.requireGuestOnly + let requireAuth: apis.requireAuth + let requireSuperuserAuth: apis.requireSuperuserAuth + let requireSuperuserOrOwnerAuth: apis.requireSuperuserOrOwnerAuth + let skipSuccessActivityLog: apis.skipSuccessActivityLog + let gzip: apis.gzip + let bodyLimit: apis.bodyLimit + let enrichRecord: apis.enrichRecord + let enrichRecords: apis.enrichRecords + + /** + * RecordAuthResponse writes standardized json record auth response + * into the specified request event. + * + * The authMethod argument specify the name of the current authentication method (eg. password, oauth2, etc.) + * that it is used primarily as an auth identifier during MFA and for login alerts. + * + * Set authMethod to empty string if you want to ignore the MFA checks and the login alerts + * (can be also adjusted additionally via the onRecordAuthRequest hook). + */ + export function recordAuthResponse(e: core.RequestEvent, authRecord: core.Record, authMethod: string, meta?: any): void } -interface RecordPasswordResetConfirmForm extends forms.RecordPasswordResetConfirm{} // merge -/** - * @inheritDoc - * @group PocketBase - */ -declare class RecordPasswordResetConfirmForm implements forms.RecordPasswordResetConfirm { - constructor(app: CoreApp, collection: models.Collection) +// ------------------------------------------------------------------- +// httpClientBinds +// ------------------------------------------------------------------- + +// extra FormData overload to prevent TS warnings when used with non File/Blob value. +interface FormData { + append(key:string, value:any): void + set(key:string, value:any): void } -interface RecordPasswordResetRequestForm extends forms.RecordPasswordResetRequest{} // merge /** - * @inheritDoc - * @group PocketBase - */ -declare class RecordPasswordResetRequestForm implements forms.RecordPasswordResetRequest { - constructor(app: CoreApp, collection: models.Collection) -} - -interface RecordUpsertForm extends forms.RecordUpsert{} // merge -/** - * @inheritDoc - * @group PocketBase - */ -declare class RecordUpsertForm implements forms.RecordUpsert { - constructor(app: CoreApp, record: models.Record) -} - -interface RecordVerificationConfirmForm extends forms.RecordVerificationConfirm{} // merge -/** - * @inheritDoc - * @group PocketBase - */ -declare class RecordVerificationConfirmForm implements forms.RecordVerificationConfirm { - constructor(app: CoreApp, collection: models.Collection) -} - -interface RecordVerificationRequestForm extends forms.RecordVerificationRequest{} // merge -/** - * @inheritDoc - * @group PocketBase - */ -declare class RecordVerificationRequestForm implements forms.RecordVerificationRequest { - constructor(app: CoreApp, collection: models.Collection) -} - -interface SettingsUpsertForm extends forms.SettingsUpsert{} // merge -/** - * @inheritDoc - * @group PocketBase - */ -declare class SettingsUpsertForm implements forms.SettingsUpsert { - constructor(app: CoreApp) -} - -interface TestEmailSendForm extends forms.TestEmailSend{} // merge -/** - * @inheritDoc - * @group PocketBase - */ -declare class TestEmailSendForm implements forms.TestEmailSend { - constructor(app: CoreApp) -} - -interface TestS3FilesystemForm extends forms.TestS3Filesystem{} // merge -/** - * @inheritDoc - * @group PocketBase - */ -declare class TestS3FilesystemForm implements forms.TestS3Filesystem { - constructor(app: CoreApp) -} - -// ------------------------------------------------------------------- -// apisBinds -// ------------------------------------------------------------------- - -interface ApiError extends apis.ApiError{} // merge -/** - * @inheritDoc - * - * @group PocketBase - */ -declare class ApiError implements apis.ApiError { - constructor(status?: number, message?: string, data?: any) -} - -interface NotFoundError extends apis.ApiError{} // merge -/** - * NotFounderor returns 404 ApiError. - * - * @group PocketBase - */ -declare class NotFoundError implements apis.ApiError { - constructor(message?: string, data?: any) -} - -interface BadRequestError extends apis.ApiError{} // merge -/** - * BadRequestError returns 400 ApiError. - * - * @group PocketBase - */ -declare class BadRequestError implements apis.ApiError { - constructor(message?: string, data?: any) -} - -interface ForbiddenError extends apis.ApiError{} // merge -/** - * ForbiddenError returns 403 ApiError. - * - * @group PocketBase - */ -declare class ForbiddenError implements apis.ApiError { - constructor(message?: string, data?: any) -} - -interface UnauthorizedError extends apis.ApiError{} // merge -/** - * UnauthorizedError returns 401 ApiError. - * - * @group PocketBase - */ -declare class UnauthorizedError implements apis.ApiError { - constructor(message?: string, data?: any) -} - -/** - * `$apis` defines commonly used PocketBase api helpers and middlewares. - * - * @group PocketBase - */ -declare namespace $apis { - /** - * Route handler to serve static directory content (html, js, css, etc.). - * - * If a file resource is missing and indexFallback is set, the request - * will be forwarded to the base index.html (useful for SPA). - */ - export function staticDirectoryHandler(dir: string, indexFallback: boolean): echo.HandlerFunc - - let requireGuestOnly: apis.requireGuestOnly - let requireRecordAuth: apis.requireRecordAuth - let requireAdminAuth: apis.requireAdminAuth - let requireAdminAuthOnlyIfAny: apis.requireAdminAuthOnlyIfAny - let requireAdminOrRecordAuth: apis.requireAdminOrRecordAuth - let requireAdminOrOwnerAuth: apis.requireAdminOrOwnerAuth - let activityLogger: apis.activityLogger - let requestInfo: apis.requestInfo - let recordAuthResponse: apis.recordAuthResponse - let gzip: middleware.gzip - let bodyLimit: middleware.bodyLimit - let enrichRecord: apis.enrichRecord - let enrichRecords: apis.enrichRecords -} - -// ------------------------------------------------------------------- -// httpClientBinds -// ------------------------------------------------------------------- - -// extra FormData overload to prevent TS warnings when used with non File/Blob value. -interface FormData { - append(key:string, value:any): void - set(key:string, value:any): void -} - -/** - * `$http` defines common methods for working with HTTP requests. - * + * `$http` defines common methods for working with HTTP requests. + * * @group PocketBase */ declare namespace $http { @@ -1019,15 +1105,16 @@ declare namespace $http { * * ```js * const res = $http.send({ - * url: "https://example.com", - * body: JSON.stringify({"title": "test"}) - * method: "post", + * method: "POST", + * url: "https://example.com", + * body: JSON.stringify({"title": "test"}), + * headers: { 'Content-Type': 'application/json' } * }) * * console.log(res.statusCode) // the response HTTP status code * console.log(res.headers) // the response headers (eg. res.headers['X-Custom'][0]) * console.log(res.cookies) // the response cookies (eg. res.cookies.sessionId.value) - * console.log(res.raw) // the response body as plain text + * console.log(res.body) // the response body as raw bytes slice * console.log(res.json) // the response body as parsed json array or map * ``` */ @@ -1038,14 +1125,17 @@ declare namespace $http { headers?: { [key:string]: string }, timeout?: number, // default to 120 - // deprecated, please use body instead + // @deprecated please use body instead data?: { [key:string]: any }, }): { statusCode: number, headers: { [key:string]: Array }, cookies: { [key:string]: http.Cookie }, - raw: string, json: any, + body: Array, + + // @deprecated please use toString(result.body) instead + raw: string, }; } @@ -1061,96 +1151,90 @@ declare namespace $http { * @group PocketBase */ declare function migrate( - up: (db: dbx.Builder) => void, - down?: (db: dbx.Builder) => void + up: (txApp: CoreApp) => void, + down?: (txApp: CoreApp) => void ): void; -/** @group PocketBase */declare function onAdminAfterAuthRefreshRequest(handler: (e: core.AdminAuthRefreshEvent) => void): void -/** @group PocketBase */declare function onAdminAfterAuthWithPasswordRequest(handler: (e: core.AdminAuthWithPasswordEvent) => void): void -/** @group PocketBase */declare function onAdminAfterConfirmPasswordResetRequest(handler: (e: core.AdminConfirmPasswordResetEvent) => void): void -/** @group PocketBase */declare function onAdminAfterCreateRequest(handler: (e: core.AdminCreateEvent) => void): void -/** @group PocketBase */declare function onAdminAfterDeleteRequest(handler: (e: core.AdminDeleteEvent) => void): void -/** @group PocketBase */declare function onAdminAfterRequestPasswordResetRequest(handler: (e: core.AdminRequestPasswordResetEvent) => void): void -/** @group PocketBase */declare function onAdminAfterUpdateRequest(handler: (e: core.AdminUpdateEvent) => void): void -/** @group PocketBase */declare function onAdminAuthRequest(handler: (e: core.AdminAuthEvent) => void): void -/** @group PocketBase */declare function onAdminBeforeAuthRefreshRequest(handler: (e: core.AdminAuthRefreshEvent) => void): void -/** @group PocketBase */declare function onAdminBeforeAuthWithPasswordRequest(handler: (e: core.AdminAuthWithPasswordEvent) => void): void -/** @group PocketBase */declare function onAdminBeforeConfirmPasswordResetRequest(handler: (e: core.AdminConfirmPasswordResetEvent) => void): void -/** @group PocketBase */declare function onAdminBeforeCreateRequest(handler: (e: core.AdminCreateEvent) => void): void -/** @group PocketBase */declare function onAdminBeforeDeleteRequest(handler: (e: core.AdminDeleteEvent) => void): void -/** @group PocketBase */declare function onAdminBeforeRequestPasswordResetRequest(handler: (e: core.AdminRequestPasswordResetEvent) => void): void -/** @group PocketBase */declare function onAdminBeforeUpdateRequest(handler: (e: core.AdminUpdateEvent) => void): void -/** @group PocketBase */declare function onAdminViewRequest(handler: (e: core.AdminViewEvent) => void): void -/** @group PocketBase */declare function onAdminsListRequest(handler: (e: core.AdminsListEvent) => void): void -/** @group PocketBase */declare function onAfterApiError(handler: (e: core.ApiErrorEvent) => void): void -/** @group PocketBase */declare function onAfterBootstrap(handler: (e: core.BootstrapEvent) => void): void -/** @group PocketBase */declare function onBeforeApiError(handler: (e: core.ApiErrorEvent) => void): void -/** @group PocketBase */declare function onBeforeBootstrap(handler: (e: core.BootstrapEvent) => void): void -/** @group PocketBase */declare function onCollectionAfterCreateRequest(handler: (e: core.CollectionCreateEvent) => void): void -/** @group PocketBase */declare function onCollectionAfterDeleteRequest(handler: (e: core.CollectionDeleteEvent) => void): void -/** @group PocketBase */declare function onCollectionAfterUpdateRequest(handler: (e: core.CollectionUpdateEvent) => void): void -/** @group PocketBase */declare function onCollectionBeforeCreateRequest(handler: (e: core.CollectionCreateEvent) => void): void -/** @group PocketBase */declare function onCollectionBeforeDeleteRequest(handler: (e: core.CollectionDeleteEvent) => void): void -/** @group PocketBase */declare function onCollectionBeforeUpdateRequest(handler: (e: core.CollectionUpdateEvent) => void): void -/** @group PocketBase */declare function onCollectionViewRequest(handler: (e: core.CollectionViewEvent) => void): void -/** @group PocketBase */declare function onCollectionsAfterImportRequest(handler: (e: core.CollectionsImportEvent) => void): void -/** @group PocketBase */declare function onCollectionsBeforeImportRequest(handler: (e: core.CollectionsImportEvent) => void): void -/** @group PocketBase */declare function onCollectionsListRequest(handler: (e: core.CollectionsListEvent) => void): void -/** @group PocketBase */declare function onFileAfterTokenRequest(handler: (e: core.FileTokenEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onFileBeforeTokenRequest(handler: (e: core.FileTokenEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onFileDownloadRequest(handler: (e: core.FileDownloadEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onMailerAfterAdminResetPasswordSend(handler: (e: core.MailerAdminEvent) => void): void -/** @group PocketBase */declare function onMailerAfterRecordChangeEmailSend(handler: (e: core.MailerRecordEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onMailerAfterRecordResetPasswordSend(handler: (e: core.MailerRecordEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onMailerAfterRecordVerificationSend(handler: (e: core.MailerRecordEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onMailerBeforeAdminResetPasswordSend(handler: (e: core.MailerAdminEvent) => void): void -/** @group PocketBase */declare function onMailerBeforeRecordChangeEmailSend(handler: (e: core.MailerRecordEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onMailerBeforeRecordResetPasswordSend(handler: (e: core.MailerRecordEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onMailerBeforeRecordVerificationSend(handler: (e: core.MailerRecordEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onModelAfterCreate(handler: (e: core.ModelEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onModelAfterDelete(handler: (e: core.ModelEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onModelAfterUpdate(handler: (e: core.ModelEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onModelBeforeCreate(handler: (e: core.ModelEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onModelBeforeDelete(handler: (e: core.ModelEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onModelBeforeUpdate(handler: (e: core.ModelEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRealtimeAfterMessageSend(handler: (e: core.RealtimeMessageEvent) => void): void -/** @group PocketBase */declare function onRealtimeAfterSubscribeRequest(handler: (e: core.RealtimeSubscribeEvent) => void): void -/** @group PocketBase */declare function onRealtimeBeforeMessageSend(handler: (e: core.RealtimeMessageEvent) => void): void -/** @group PocketBase */declare function onRealtimeBeforeSubscribeRequest(handler: (e: core.RealtimeSubscribeEvent) => void): void -/** @group PocketBase */declare function onRealtimeConnectRequest(handler: (e: core.RealtimeConnectEvent) => void): void -/** @group PocketBase */declare function onRealtimeDisconnectRequest(handler: (e: core.RealtimeDisconnectEvent) => void): void -/** @group PocketBase */declare function onRecordAfterAuthRefreshRequest(handler: (e: core.RecordAuthRefreshEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordAfterAuthWithOAuth2Request(handler: (e: core.RecordAuthWithOAuth2Event) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordAfterAuthWithPasswordRequest(handler: (e: core.RecordAuthWithPasswordEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordAfterConfirmEmailChangeRequest(handler: (e: core.RecordConfirmEmailChangeEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordAfterConfirmPasswordResetRequest(handler: (e: core.RecordConfirmPasswordResetEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordAfterConfirmVerificationRequest(handler: (e: core.RecordConfirmVerificationEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordAfterCreateRequest(handler: (e: core.RecordCreateEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordAfterDeleteRequest(handler: (e: core.RecordDeleteEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordAfterRequestEmailChangeRequest(handler: (e: core.RecordRequestEmailChangeEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordAfterRequestPasswordResetRequest(handler: (e: core.RecordRequestPasswordResetEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordAfterRequestVerificationRequest(handler: (e: core.RecordRequestVerificationEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordAfterUnlinkExternalAuthRequest(handler: (e: core.RecordUnlinkExternalAuthEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordAfterUpdateRequest(handler: (e: core.RecordUpdateEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordAuthRequest(handler: (e: core.RecordAuthEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordBeforeAuthRefreshRequest(handler: (e: core.RecordAuthRefreshEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordBeforeAuthWithOAuth2Request(handler: (e: core.RecordAuthWithOAuth2Event) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordBeforeAuthWithPasswordRequest(handler: (e: core.RecordAuthWithPasswordEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordBeforeConfirmEmailChangeRequest(handler: (e: core.RecordConfirmEmailChangeEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordBeforeConfirmPasswordResetRequest(handler: (e: core.RecordConfirmPasswordResetEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordBeforeConfirmVerificationRequest(handler: (e: core.RecordConfirmVerificationEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordBeforeCreateRequest(handler: (e: core.RecordCreateEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordBeforeDeleteRequest(handler: (e: core.RecordDeleteEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordBeforeRequestEmailChangeRequest(handler: (e: core.RecordRequestEmailChangeEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordBeforeRequestPasswordResetRequest(handler: (e: core.RecordRequestPasswordResetEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordBeforeRequestVerificationRequest(handler: (e: core.RecordRequestVerificationEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordBeforeUnlinkExternalAuthRequest(handler: (e: core.RecordUnlinkExternalAuthEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordBeforeUpdateRequest(handler: (e: core.RecordUpdateEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordListExternalAuthsRequest(handler: (e: core.RecordListExternalAuthsEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordViewRequest(handler: (e: core.RecordViewEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onRecordsListRequest(handler: (e: core.RecordsListEvent) => void, ...tags: string[]): void -/** @group PocketBase */declare function onSettingsAfterUpdateRequest(handler: (e: core.SettingsUpdateEvent) => void): void -/** @group PocketBase */declare function onSettingsBeforeUpdateRequest(handler: (e: core.SettingsUpdateEvent) => void): void -/** @group PocketBase */declare function onSettingsListRequest(handler: (e: core.SettingsListEvent) => void): void +/** @group PocketBase */declare function onBackupCreate(handler: (e: core.BackupEvent) => void): void +/** @group PocketBase */declare function onBackupRestore(handler: (e: core.BackupEvent) => void): void +/** @group PocketBase */declare function onBatchRequest(handler: (e: core.BatchRequestEvent) => void): void +/** @group PocketBase */declare function onBootstrap(handler: (e: core.BootstrapEvent) => void): void +/** @group PocketBase */declare function onCollectionAfterCreateError(handler: (e: core.CollectionErrorEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onCollectionAfterCreateSuccess(handler: (e: core.CollectionEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onCollectionAfterDeleteError(handler: (e: core.CollectionErrorEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onCollectionAfterDeleteSuccess(handler: (e: core.CollectionEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onCollectionAfterUpdateError(handler: (e: core.CollectionErrorEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onCollectionAfterUpdateSuccess(handler: (e: core.CollectionEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onCollectionCreate(handler: (e: core.CollectionEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onCollectionCreateExecute(handler: (e: core.CollectionEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onCollectionCreateRequest(handler: (e: core.CollectionRequestEvent) => void): void +/** @group PocketBase */declare function onCollectionDelete(handler: (e: core.CollectionEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onCollectionDeleteExecute(handler: (e: core.CollectionEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onCollectionDeleteRequest(handler: (e: core.CollectionRequestEvent) => void): void +/** @group PocketBase */declare function onCollectionUpdate(handler: (e: core.CollectionEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onCollectionUpdateExecute(handler: (e: core.CollectionEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onCollectionUpdateRequest(handler: (e: core.CollectionRequestEvent) => void): void +/** @group PocketBase */declare function onCollectionValidate(handler: (e: core.CollectionEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onCollectionViewRequest(handler: (e: core.CollectionRequestEvent) => void): void +/** @group PocketBase */declare function onCollectionsImportRequest(handler: (e: core.CollectionsImportRequestEvent) => void): void +/** @group PocketBase */declare function onCollectionsListRequest(handler: (e: core.CollectionsListRequestEvent) => void): void +/** @group PocketBase */declare function onFileDownloadRequest(handler: (e: core.FileDownloadRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onFileTokenRequest(handler: (e: core.FileTokenRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onMailerRecordAuthAlertSend(handler: (e: core.MailerRecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onMailerRecordEmailChangeSend(handler: (e: core.MailerRecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onMailerRecordOTPSend(handler: (e: core.MailerRecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onMailerRecordPasswordResetSend(handler: (e: core.MailerRecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onMailerRecordVerificationSend(handler: (e: core.MailerRecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onMailerSend(handler: (e: core.MailerEvent) => void): void +/** @group PocketBase */declare function onModelAfterCreateError(handler: (e: core.ModelErrorEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onModelAfterCreateSuccess(handler: (e: core.ModelEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onModelAfterDeleteError(handler: (e: core.ModelErrorEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onModelAfterDeleteSuccess(handler: (e: core.ModelEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onModelAfterUpdateError(handler: (e: core.ModelErrorEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onModelAfterUpdateSuccess(handler: (e: core.ModelEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onModelCreate(handler: (e: core.ModelEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onModelCreateExecute(handler: (e: core.ModelEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onModelDelete(handler: (e: core.ModelEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onModelDeleteExecute(handler: (e: core.ModelEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onModelUpdate(handler: (e: core.ModelEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onModelUpdateExecute(handler: (e: core.ModelEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onModelValidate(handler: (e: core.ModelEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRealtimeConnectRequest(handler: (e: core.RealtimeConnectRequestEvent) => void): void +/** @group PocketBase */declare function onRealtimeMessageSend(handler: (e: core.RealtimeMessageEvent) => void): void +/** @group PocketBase */declare function onRealtimeSubscribeRequest(handler: (e: core.RealtimeSubscribeRequestEvent) => void): void +/** @group PocketBase */declare function onRecordAfterCreateError(handler: (e: core.RecordErrorEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordAfterCreateSuccess(handler: (e: core.RecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordAfterDeleteError(handler: (e: core.RecordErrorEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordAfterDeleteSuccess(handler: (e: core.RecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordAfterUpdateError(handler: (e: core.RecordErrorEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordAfterUpdateSuccess(handler: (e: core.RecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordAuthRefreshRequest(handler: (e: core.RecordAuthRefreshRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordAuthRequest(handler: (e: core.RecordAuthRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordAuthWithOAuth2Request(handler: (e: core.RecordAuthWithOAuth2RequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordAuthWithOTPRequest(handler: (e: core.RecordAuthWithOTPRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordAuthWithPasswordRequest(handler: (e: core.RecordAuthWithPasswordRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordConfirmEmailChangeRequest(handler: (e: core.RecordConfirmEmailChangeRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordConfirmPasswordResetRequest(handler: (e: core.RecordConfirmPasswordResetRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordConfirmVerificationRequest(handler: (e: core.RecordConfirmVerificationRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordCreate(handler: (e: core.RecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordCreateExecute(handler: (e: core.RecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordCreateRequest(handler: (e: core.RecordRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordDelete(handler: (e: core.RecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordDeleteExecute(handler: (e: core.RecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordDeleteRequest(handler: (e: core.RecordRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordEnrich(handler: (e: core.RecordEnrichEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordRequestEmailChangeRequest(handler: (e: core.RecordRequestEmailChangeRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordRequestOTPRequest(handler: (e: core.RecordCreateOTPRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordRequestPasswordResetRequest(handler: (e: core.RecordRequestPasswordResetRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordRequestVerificationRequest(handler: (e: core.RecordRequestVerificationRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordUpdate(handler: (e: core.RecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordUpdateExecute(handler: (e: core.RecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordUpdateRequest(handler: (e: core.RecordRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordValidate(handler: (e: core.RecordEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordViewRequest(handler: (e: core.RecordRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onRecordsListRequest(handler: (e: core.RecordsListRequestEvent) => void, ...tags: string[]): void +/** @group PocketBase */declare function onSettingsListRequest(handler: (e: core.SettingsListRequestEvent) => void): void +/** @group PocketBase */declare function onSettingsReload(handler: (e: core.SettingsReloadEvent) => void): void +/** @group PocketBase */declare function onSettingsUpdateRequest(handler: (e: core.SettingsUpdateRequestEvent) => void): void /** @group PocketBase */declare function onTerminate(handler: (e: core.TerminateEvent) => void): void type _TygojaDict = { [key:string | number | symbol]: any; } type _TygojaAny = any @@ -1294,6 +1378,9 @@ namespace os { * * Symbolic links in dir are followed. * + * New files added to fsys (including if dir is a subdirectory of fsys) + * while CopyFS is running are not guaranteed to be copied. + * * Copying stops at and returns the first error encountered. */ (dir: string, fsys: fs.FS): void @@ -1721,8 +1808,8 @@ namespace os { * than ReadFrom. This is used to permit ReadFrom to call io.Copy * without leading to a recursive call to ReadFrom. */ - type _subpQHUo = noReadFrom&File - interface fileWithoutReadFrom extends _subpQHUo { + type _sSebCtZ = noReadFrom&File + interface fileWithoutReadFrom extends _sSebCtZ { } interface File { /** @@ -1766,8 +1853,8 @@ namespace os { * than WriteTo. This is used to permit WriteTo to call io.Copy * without leading to a recursive call to WriteTo. */ - type _subUePGm = noWriteTo&File - interface fileWithoutWriteTo extends _subUePGm { + type _syRNnov = noWriteTo&File + interface fileWithoutWriteTo extends _syRNnov { } interface File { /** @@ -1816,6 +1903,7 @@ namespace os { * it is truncated. If the file does not exist, it is created with mode 0o666 * (before umask). If successful, methods on the returned File can * be used for I/O; the associated file descriptor has mode O_RDWR. + * The directory containing the file must already exist. * If there is an error, it will be of type *PathError. */ (name: string): (File) @@ -1825,7 +1913,8 @@ namespace os { * OpenFile is the generalized open call; most users will use Open * or Create instead. It opens the named file with specified flag * (O_RDONLY etc.). If the file does not exist, and the O_CREATE flag - * is passed, it is created with mode perm (before umask). If successful, + * is passed, it is created with mode perm (before umask); + * the containing directory must exist. If successful, * methods on the returned File can be used for I/O. * If there is an error, it will be of type *PathError. */ @@ -1835,6 +1924,7 @@ namespace os { /** * Rename renames (moves) oldpath to newpath. * If newpath already exists and is not a directory, Rename replaces it. + * If newpath already exists and is a directory, Rename returns an error. * OS-specific restrictions may apply when oldpath and newpath are in different directories. * Even within the same directory, on non-Unix platforms Rename is not an atomic operation. * If there is an error, it will be of type *LinkError. @@ -1878,8 +1968,8 @@ namespace os { * On Windows, it returns %LocalAppData%. * On Plan 9, it returns $home/lib/cache. * - * If the location cannot be determined (for example, $HOME is not defined), - * then it will return an error. + * If the location cannot be determined (for example, $HOME is not defined) or + * the path in $XDG_CACHE_HOME is relative, then it will return an error. */ (): string } @@ -1896,8 +1986,8 @@ namespace os { * On Windows, it returns %AppData%. * On Plan 9, it returns $home/lib. * - * If the location cannot be determined (for example, $HOME is not defined), - * then it will return an error. + * If the location cannot be determined (for example, $HOME is not defined) or + * the path in $XDG_CONFIG_HOME is relative, then it will return an error. */ (): string } @@ -2013,6 +2103,8 @@ namespace os { * a general substitute for a chroot-style security mechanism when the directory tree * contains arbitrary content. * + * Use [Root.FS] to obtain a fs.FS that prevents escapes from the tree via symbolic links. + * * The directory dir must not be "". * * The result implements [io/fs.StatFS], [io/fs.ReadFileFS] and @@ -2233,10 +2325,14 @@ namespace os { } interface getwd { /** - * Getwd returns a rooted path name corresponding to the + * Getwd returns an absolute path name corresponding to the * current directory. If the current directory can be * reached via multiple paths (due to symbolic links), * Getwd may return any one of them. + * + * On Unix platforms, if the environment variable PWD + * provides an absolute name, and it is a name of the + * current directory, it is returned. */ (): string } @@ -2340,6 +2436,183 @@ namespace os { interface rawConn { write(f: (_arg0: number) => boolean): void } + interface openInRoot { + /** + * OpenInRoot opens the file name in the directory dir. + * It is equivalent to OpenRoot(dir) followed by opening the file in the root. + * + * OpenInRoot returns an error if any component of the name + * references a location outside of dir. + * + * See [Root] for details and limitations. + */ + (dir: string, name: string): (File) + } + /** + * Root may be used to only access files within a single directory tree. + * + * Methods on Root can only access files and directories beneath a root directory. + * If any component of a file name passed to a method of Root references a location + * outside the root, the method returns an error. + * File names may reference the directory itself (.). + * + * Methods on Root will follow symbolic links, but symbolic links may not + * reference a location outside the root. + * Symbolic links must not be absolute. + * + * Methods on Root do not prohibit traversal of filesystem boundaries, + * Linux bind mounts, /proc special files, or access to Unix device files. + * + * Methods on Root are safe to be used from multiple goroutines simultaneously. + * + * On most platforms, creating a Root opens a file descriptor or handle referencing + * the directory. If the directory is moved, methods on Root reference the original + * directory in its new location. + * + * Root's behavior differs on some platforms: + * + * ``` + * - When GOOS=windows, file names may not reference Windows reserved device names + * such as NUL and COM1. + * - When GOOS=js, Root is vulnerable to TOCTOU (time-of-check-time-of-use) + * attacks in symlink validation, and cannot ensure that operations will not + * escape the root. + * - When GOOS=plan9 or GOOS=js, Root does not track directories across renames. + * On these platforms, a Root references a directory name, not a file descriptor. + * ``` + */ + interface Root { + } + interface openRoot { + /** + * OpenRoot opens the named directory. + * If there is an error, it will be of type *PathError. + */ + (name: string): (Root) + } + interface Root { + /** + * Name returns the name of the directory presented to OpenRoot. + * + * It is safe to call Name after [Close]. + */ + name(): string + } + interface Root { + /** + * Close closes the Root. + * After Close is called, methods on Root return errors. + */ + close(): void + } + interface Root { + /** + * Open opens the named file in the root for reading. + * See [Open] for more details. + */ + open(name: string): (File) + } + interface Root { + /** + * Create creates or truncates the named file in the root. + * See [Create] for more details. + */ + create(name: string): (File) + } + interface Root { + /** + * OpenFile opens the named file in the root. + * See [OpenFile] for more details. + * + * If perm contains bits other than the nine least-significant bits (0o777), + * OpenFile returns an error. + */ + openFile(name: string, flag: number, perm: FileMode): (File) + } + interface Root { + /** + * OpenRoot opens the named directory in the root. + * If there is an error, it will be of type *PathError. + */ + openRoot(name: string): (Root) + } + interface Root { + /** + * Mkdir creates a new directory in the root + * with the specified name and permission bits (before umask). + * See [Mkdir] for more details. + * + * If perm contains bits other than the nine least-significant bits (0o777), + * OpenFile returns an error. + */ + mkdir(name: string, perm: FileMode): void + } + interface Root { + /** + * Remove removes the named file or (empty) directory in the root. + * See [Remove] for more details. + */ + remove(name: string): void + } + interface Root { + /** + * Stat returns a [FileInfo] describing the named file in the root. + * See [Stat] for more details. + */ + stat(name: string): FileInfo + } + interface Root { + /** + * Lstat returns a [FileInfo] describing the named file in the root. + * If the file is a symbolic link, the returned FileInfo + * describes the symbolic link. + * See [Lstat] for more details. + */ + lstat(name: string): FileInfo + } + interface Root { + /** + * FS returns a file system (an fs.FS) for the tree of files in the root. + * + * The result implements [io/fs.StatFS], [io/fs.ReadFileFS] and + * [io/fs.ReadDirFS]. + */ + fs(): fs.FS + } + interface rootFS extends Root{} + interface rootFS { + open(name: string): fs.File + } + interface rootFS { + readDir(name: string): Array + } + interface rootFS { + readFile(name: string): string|Array + } + interface rootFS { + stat(name: string): FileInfo + } + /** + * root implementation for platforms with a function to open a file + * relative to a directory. + */ + interface root { + } + interface root { + close(): void + } + interface root { + name(): string + } + /** + * errSymlink reports that a file being operated on is actually a symlink, + * and the target of that symlink. + */ + interface errSymlink extends String{} + interface errSymlink { + error(): string + } + interface sysfdType extends Number{} interface stat { /** * Stat returns a [FileInfo] describing the named file. @@ -2411,8 +2684,8 @@ namespace os { * * The methods of File are safe for concurrent use. */ - type _subGANfA = file - interface File extends _subGANfA { + type _sxAWdxp = file + interface File extends _sxAWdxp { } /** * A FileInfo describes a file and is returned by [Stat] and [Lstat]. @@ -2804,264 +3077,41 @@ namespace filepath { } } -namespace security { - interface s256Challenge { - /** - * S256Challenge creates base64 encoded sha256 challenge string derived from code. - * The padding of the result base64 string is stripped per [RFC 7636]. - * - * [RFC 7636]: https://datatracker.ietf.org/doc/html/rfc7636#section-4.2 - */ - (code: string): string +/** + * Package validation provides configurable and extensible rules for validating data of various types. + */ +namespace ozzo_validation { + /** + * Error interface represents an validation error + */ + interface Error { + [key:string]: any; + error(): string + code(): string + message(): string + setMessage(_arg0: string): Error + params(): _TygojaDict + setParams(_arg0: _TygojaDict): Error } - interface md5 { +} + +/** + * Package dbx provides a set of DB-agnostic and easy-to-use query building methods for relational databases. + */ +namespace dbx { + /** + * Builder supports building SQL statements in a DB-agnostic way. + * Builder mainly provides two sets of query building methods: those building SELECT statements + * and those manipulating DB data or schema (e.g. INSERT statements, CREATE TABLE statements). + */ + interface Builder { + [key:string]: any; /** - * MD5 creates md5 hash from the provided plain text. + * NewQuery creates a new Query object with the given SQL statement. + * The SQL statement may contain parameter placeholders which can be bound with actual parameter + * values before the statement is executed. */ - (text: string): string - } - interface sha256 { - /** - * SHA256 creates sha256 hash as defined in FIPS 180-4 from the provided text. - */ - (text: string): string - } - interface sha512 { - /** - * SHA512 creates sha512 hash as defined in FIPS 180-4 from the provided text. - */ - (text: string): string - } - interface hs256 { - /** - * HS256 creates a HMAC hash with sha256 digest algorithm. - */ - (text: string, secret: string): string - } - interface hs512 { - /** - * HS512 creates a HMAC hash with sha512 digest algorithm. - */ - (text: string, secret: string): string - } - interface equal { - /** - * Equal compares two hash strings for equality without leaking timing information. - */ - (hash1: string, hash2: string): boolean - } - // @ts-ignore - import crand = rand - interface encrypt { - /** - * Encrypt encrypts "data" with the specified "key" (must be valid 32 char AES key). - * - * This method uses AES-256-GCM block cypher mode. - */ - (data: string|Array, key: string): string - } - interface decrypt { - /** - * Decrypt decrypts encrypted text with key (must be valid 32 chars AES key). - * - * This method uses AES-256-GCM block cypher mode. - */ - (cipherText: string, key: string): string|Array - } - interface parseUnverifiedJWT { - /** - * ParseUnverifiedJWT parses JWT and returns its claims - * but DOES NOT verify the signature. - * - * It verifies only the exp, iat and nbf claims. - */ - (token: string): jwt.MapClaims - } - interface parseJWT { - /** - * ParseJWT verifies and parses JWT and returns its claims. - */ - (token: string, verificationKey: string): jwt.MapClaims - } - interface newJWT { - /** - * NewJWT generates and returns new HS256 signed JWT. - */ - (payload: jwt.MapClaims, signingKey: string, secondsDuration: number): string - } - interface newToken { - /** - * Deprecated: - * Consider replacing with NewJWT(). - * - * NewToken is a legacy alias for NewJWT that generates a HS256 signed JWT. - */ - (payload: jwt.MapClaims, signingKey: string, secondsDuration: number): string - } - // @ts-ignore - import cryptoRand = rand - // @ts-ignore - import mathRand = rand - interface randomString { - /** - * RandomString generates a cryptographically random string with the specified length. - * - * The generated string matches [A-Za-z0-9]+ and it's transparent to URL-encoding. - */ - (length: number): string - } - interface randomStringWithAlphabet { - /** - * RandomStringWithAlphabet generates a cryptographically random string - * with the specified length and characters set. - * - * It panics if for some reason rand.Int returns a non-nil error. - */ - (length: number, alphabet: string): string - } - interface pseudorandomString { - /** - * PseudorandomString generates a pseudorandom string with the specified length. - * - * The generated string matches [A-Za-z0-9]+ and it's transparent to URL-encoding. - * - * For a cryptographically random string (but a little bit slower) use RandomString instead. - */ - (length: number): string - } - interface pseudorandomStringWithAlphabet { - /** - * PseudorandomStringWithAlphabet generates a pseudorandom string - * with the specified length and characters set. - * - * For a cryptographically random (but a little bit slower) use RandomStringWithAlphabet instead. - */ - (length: number, alphabet: string): string - } -} - -/** - * Package template is a thin wrapper around the standard html/template - * and text/template packages that implements a convenient registry to - * load and cache templates on the fly concurrently. - * - * It was created to assist the JSVM plugin HTML rendering, but could be used in other Go code. - * - * Example: - * - * ``` - * registry := template.NewRegistry() - * - * html1, err := registry.LoadFiles( - * // the files set wil be parsed only once and then cached - * "layout.html", - * "content.html", - * ).Render(map[string]any{"name": "John"}) - * - * html2, err := registry.LoadFiles( - * // reuse the already parsed and cached files set - * "layout.html", - * "content.html", - * ).Render(map[string]any{"name": "Jane"}) - * ``` - */ -namespace template { - interface newRegistry { - /** - * NewRegistry creates and initializes a new templates registry with - * some defaults (eg. global "raw" template function for unescaped HTML). - * - * Use the Registry.Load* methods to load templates into the registry. - */ - (): (Registry) - } - /** - * Registry defines a templates registry that is safe to be used by multiple goroutines. - * - * Use the Registry.Load* methods to load templates into the registry. - */ - interface Registry { - } - interface Registry { - /** - * AddFuncs registers new global template functions. - * - * The key of each map entry is the function name that will be used in the templates. - * If a function with the map entry name already exists it will be replaced with the new one. - * - * The value of each map entry is a function that must have either a - * single return value, or two return values of which the second has type error. - * - * Example: - * - * r.AddFuncs(map[string]any{ - * ``` - * "toUpper": func(str string) string { - * return strings.ToUppser(str) - * }, - * ... - * ``` - * }) - */ - addFuncs(funcs: _TygojaDict): (Registry) - } - interface Registry { - /** - * LoadFiles caches (if not already) the specified filenames set as a - * single template and returns a ready to use Renderer instance. - * - * There must be at least 1 filename specified. - */ - loadFiles(...filenames: string[]): (Renderer) - } - interface Registry { - /** - * LoadString caches (if not already) the specified inline string as a - * single template and returns a ready to use Renderer instance. - */ - loadString(text: string): (Renderer) - } - interface Registry { - /** - * LoadFS caches (if not already) the specified fs and globPatterns - * pair as single template and returns a ready to use Renderer instance. - * - * There must be at least 1 file matching the provided globPattern(s) - * (note that most file names serves as glob patterns matching themselves). - */ - loadFS(fsys: fs.FS, ...globPatterns: string[]): (Renderer) - } - /** - * Renderer defines a single parsed template. - */ - interface Renderer { - } - interface Renderer { - /** - * Render executes the template with the specified data as the dot object - * and returns the result as plain string. - */ - render(data: any): string - } -} - -/** - * Package dbx provides a set of DB-agnostic and easy-to-use query building methods for relational databases. - */ -namespace dbx { - /** - * Builder supports building SQL statements in a DB-agnostic way. - * Builder mainly provides two sets of query building methods: those building SELECT statements - * and those manipulating DB data or schema (e.g. INSERT statements, CREATE TABLE statements). - */ - interface Builder { - [key:string]: any; - /** - * NewQuery creates a new Query object with the given SQL statement. - * The SQL statement may contain parameter placeholders which can be bound with actual parameter - * values before the statement is executed. - */ - newQuery(_arg0: string): (Query) + newQuery(_arg0: string): (Query) /** * Select returns a new SelectQuery object that can be used to build a SELECT statement. * The parameters to this method should be the list column names to be selected. @@ -3381,14 +3431,14 @@ namespace dbx { /** * MssqlBuilder is the builder for SQL Server databases. */ - type _subEPLIN = BaseBuilder - interface MssqlBuilder extends _subEPLIN { + type _sncGFRB = BaseBuilder + interface MssqlBuilder extends _sncGFRB { } /** * MssqlQueryBuilder is the query builder for SQL Server databases. */ - type _subiJSYo = BaseQueryBuilder - interface MssqlQueryBuilder extends _subiJSYo { + type _srekqIj = BaseQueryBuilder + interface MssqlQueryBuilder extends _srekqIj { } interface newMssqlBuilder { /** @@ -3459,8 +3509,8 @@ namespace dbx { /** * MysqlBuilder is the builder for MySQL databases. */ - type _subMhtIq = BaseBuilder - interface MysqlBuilder extends _subMhtIq { + type _sXcIrWA = BaseBuilder + interface MysqlBuilder extends _sXcIrWA { } interface newMysqlBuilder { /** @@ -3535,14 +3585,14 @@ namespace dbx { /** * OciBuilder is the builder for Oracle databases. */ - type _subRBquP = BaseBuilder - interface OciBuilder extends _subRBquP { + type _sNlFAKj = BaseBuilder + interface OciBuilder extends _sNlFAKj { } /** * OciQueryBuilder is the query builder for Oracle databases. */ - type _subENSNc = BaseQueryBuilder - interface OciQueryBuilder extends _subENSNc { + type _sGNjgDr = BaseQueryBuilder + interface OciQueryBuilder extends _sGNjgDr { } interface newOciBuilder { /** @@ -3605,8 +3655,8 @@ namespace dbx { /** * PgsqlBuilder is the builder for PostgreSQL databases. */ - type _subsShLv = BaseBuilder - interface PgsqlBuilder extends _subsShLv { + type _sMdYcQC = BaseBuilder + interface PgsqlBuilder extends _sMdYcQC { } interface newPgsqlBuilder { /** @@ -3673,8 +3723,8 @@ namespace dbx { /** * SqliteBuilder is the builder for SQLite databases. */ - type _subeBnpF = BaseBuilder - interface SqliteBuilder extends _subeBnpF { + type _sdHxMFG = BaseBuilder + interface SqliteBuilder extends _sdHxMFG { } interface newSqliteBuilder { /** @@ -3773,8 +3823,8 @@ namespace dbx { /** * StandardBuilder is the builder that is used by DB for an unknown driver. */ - type _subgxMwo = BaseBuilder - interface StandardBuilder extends _subgxMwo { + type _svvTlHa = BaseBuilder + interface StandardBuilder extends _svvTlHa { } interface newStandardBuilder { /** @@ -3840,8 +3890,8 @@ namespace dbx { * DB enhances sql.DB by providing a set of DB-agnostic query building methods. * DB allows easier query building and population of data into Go variables. */ - type _subnBTRt = Builder - interface DB extends _subnBTRt { + type _sDZeZLW = Builder + interface DB extends _sDZeZLW { /** * FieldMapper maps struct fields to DB columns. Defaults to DefaultFieldMapFunc. */ @@ -4645,8 +4695,8 @@ namespace dbx { * Rows enhances sql.Rows by providing additional data query methods. * Rows can be obtained by calling Query.Rows(). It is mainly used to populate data row by row. */ - type _subuSGqA = sql.Rows - interface Rows extends _subuSGqA { + type _sXXoPjA = sql.Rows + interface Rows extends _sXXoPjA { } interface Rows { /** @@ -4732,6 +4782,18 @@ namespace dbx { */ withContext(ctx: context.Context): (SelectQuery) } + interface SelectQuery { + /** + * PreFragment sets SQL fragment that should be prepended before the select query (e.g. WITH clause). + */ + preFragment(fragment: string): (SelectQuery) + } + interface SelectQuery { + /** + * PostFragment sets SQL fragment that should be appended at the end of the select query. + */ + postFragment(fragment: string): (SelectQuery) + } interface SelectQuery { /** * Select specifies the columns to be selected. @@ -4969,6 +5031,8 @@ namespace dbx { * QueryInfo represents a debug/info struct with exported SelectQuery fields. */ interface QueryInfo { + preFragment: string + postFragment: string builder: Builder selects: Array distinct: boolean @@ -5004,8 +5068,8 @@ namespace dbx { }): string } interface structInfo { } - type _subKbJZd = structInfo - interface structValue extends _subKbJZd { + type _sPazdev = structInfo + interface structValue extends _sPazdev { } interface fieldInfo { } @@ -5044,8 +5108,8 @@ namespace dbx { /** * Tx enhances sql.Tx with additional querying methods. */ - type _subYNhcn = Builder - interface Tx extends _subYNhcn { + type _sKHoHWi = Builder + interface Tx extends _sKHoHWi { } interface Tx { /** @@ -5061,147 +5125,146 @@ namespace dbx { } } -/** - * Package validation provides configurable and extensible rules for validating data of various types. - */ -namespace ozzo_validation { - /** - * Error interface represents an validation error - */ - interface Error { - [key:string]: any; - error(): string - code(): string - message(): string - setMessage(_arg0: string): Error - params(): _TygojaDict - setParams(_arg0: _TygojaDict): Error - } -} - -/** - * Package exec runs external commands. It wraps os.StartProcess to make it - * easier to remap stdin and stdout, connect I/O with pipes, and do other - * adjustments. - * - * Unlike the "system" library call from C and other languages, the - * os/exec package intentionally does not invoke the system shell and - * does not expand any glob patterns or handle other expansions, - * pipelines, or redirections typically done by shells. The package - * behaves more like C's "exec" family of functions. To expand glob - * patterns, either call the shell directly, taking care to escape any - * dangerous input, or use the [path/filepath] package's Glob function. - * To expand environment variables, use package os's ExpandEnv. - * - * Note that the examples in this package assume a Unix system. - * They may not run on Windows, and they do not run in the Go Playground - * used by golang.org and godoc.org. - * - * # Executables in the current directory - * - * The functions [Command] and [LookPath] look for a program - * in the directories listed in the current path, following the - * conventions of the host operating system. - * Operating systems have for decades included the current - * directory in this search, sometimes implicitly and sometimes - * configured explicitly that way by default. - * Modern practice is that including the current directory - * is usually unexpected and often leads to security problems. - * - * To avoid those security problems, as of Go 1.19, this package will not resolve a program - * using an implicit or explicit path entry relative to the current directory. - * That is, if you run [LookPath]("go"), it will not successfully return - * ./go on Unix nor .\go.exe on Windows, no matter how the path is configured. - * Instead, if the usual path algorithms would result in that answer, - * these functions return an error err satisfying [errors.Is](err, [ErrDot]). - * - * For example, consider these two program snippets: - * - * ``` - * path, err := exec.LookPath("prog") - * if err != nil { - * log.Fatal(err) - * } - * use(path) - * ``` - * - * and - * - * ``` - * cmd := exec.Command("prog") - * if err := cmd.Run(); err != nil { - * log.Fatal(err) - * } - * ``` - * - * These will not find and run ./prog or .\prog.exe, - * no matter how the current path is configured. - * - * Code that always wants to run a program from the current directory - * can be rewritten to say "./prog" instead of "prog". - * - * Code that insists on including results from relative path entries - * can instead override the error using an errors.Is check: - * - * ``` - * path, err := exec.LookPath("prog") - * if errors.Is(err, exec.ErrDot) { - * err = nil - * } - * if err != nil { - * log.Fatal(err) - * } - * use(path) - * ``` - * - * and - * - * ``` - * cmd := exec.Command("prog") - * if errors.Is(cmd.Err, exec.ErrDot) { - * cmd.Err = nil - * } - * if err := cmd.Run(); err != nil { - * log.Fatal(err) - * } - * ``` - * - * Setting the environment variable GODEBUG=execerrdot=0 - * disables generation of ErrDot entirely, temporarily restoring the pre-Go 1.19 - * behavior for programs that are unable to apply more targeted fixes. - * A future version of Go may remove support for this variable. - * - * Before adding such overrides, make sure you understand the - * security implications of doing so. - * See https://go.dev/blog/path-security for more information. - */ -namespace exec { - interface command { +namespace security { + interface s256Challenge { /** - * Command returns the [Cmd] struct to execute the named program with - * the given arguments. + * S256Challenge creates base64 encoded sha256 challenge string derived from code. + * The padding of the result base64 string is stripped per [RFC 7636]. * - * It sets only the Path and Args in the returned structure. + * [RFC 7636]: https://datatracker.ietf.org/doc/html/rfc7636#section-4.2 + */ + (code: string): string + } + interface md5 { + /** + * MD5 creates md5 hash from the provided plain text. + */ + (text: string): string + } + interface sha256 { + /** + * SHA256 creates sha256 hash as defined in FIPS 180-4 from the provided text. + */ + (text: string): string + } + interface sha512 { + /** + * SHA512 creates sha512 hash as defined in FIPS 180-4 from the provided text. + */ + (text: string): string + } + interface hs256 { + /** + * HS256 creates a HMAC hash with sha256 digest algorithm. + */ + (text: string, secret: string): string + } + interface hs512 { + /** + * HS512 creates a HMAC hash with sha512 digest algorithm. + */ + (text: string, secret: string): string + } + interface equal { + /** + * Equal compares two hash strings for equality without leaking timing information. + */ + (hash1: string, hash2: string): boolean + } + // @ts-ignore + import crand = rand + interface encrypt { + /** + * Encrypt encrypts "data" with the specified "key" (must be valid 32 char AES key). * - * If name contains no path separators, Command uses [LookPath] to - * resolve name to a complete path if possible. Otherwise it uses name - * directly as Path. + * This method uses AES-256-GCM block cypher mode. + */ + (data: string|Array, key: string): string + } + interface decrypt { + /** + * Decrypt decrypts encrypted text with key (must be valid 32 chars AES key). * - * The returned Cmd's Args field is constructed from the command name - * followed by the elements of arg, so arg should not include the - * command name itself. For example, Command("echo", "hello"). - * Args[0] is always name, not the possibly resolved Path. + * This method uses AES-256-GCM block cypher mode. + */ + (cipherText: string, key: string): string|Array + } + interface parseUnverifiedJWT { + /** + * ParseUnverifiedJWT parses JWT and returns its claims + * but DOES NOT verify the signature. * - * On Windows, processes receive the whole command line as a single string - * and do their own parsing. Command combines and quotes Args into a command - * line string with an algorithm compatible with applications using - * CommandLineToArgvW (which is the most common way). Notable exceptions are - * msiexec.exe and cmd.exe (and thus, all batch files), which have a different - * unquoting algorithm. In these or other similar cases, you can do the - * quoting yourself and provide the full command line in SysProcAttr.CmdLine, - * leaving Args empty. + * It verifies only the exp, iat and nbf claims. */ - (name: string, ...arg: string[]): (Cmd) + (token: string): jwt.MapClaims + } + interface parseJWT { + /** + * ParseJWT verifies and parses JWT and returns its claims. + */ + (token: string, verificationKey: string): jwt.MapClaims + } + interface newJWT { + /** + * NewJWT generates and returns new HS256 signed JWT. + */ + (payload: jwt.MapClaims, signingKey: string, duration: time.Duration): string + } + // @ts-ignore + import cryptoRand = rand + // @ts-ignore + import mathRand = rand + interface randomString { + /** + * RandomString generates a cryptographically random string with the specified length. + * + * The generated string matches [A-Za-z0-9]+ and it's transparent to URL-encoding. + */ + (length: number): string + } + interface randomStringWithAlphabet { + /** + * RandomStringWithAlphabet generates a cryptographically random string + * with the specified length and characters set. + * + * It panics if for some reason rand.Int returns a non-nil error. + */ + (length: number, alphabet: string): string + } + interface pseudorandomString { + /** + * PseudorandomString generates a pseudorandom string with the specified length. + * + * The generated string matches [A-Za-z0-9]+ and it's transparent to URL-encoding. + * + * For a cryptographically random string (but a little bit slower) use RandomString instead. + */ + (length: number): string + } + interface pseudorandomStringWithAlphabet { + /** + * PseudorandomStringWithAlphabet generates a pseudorandom string + * with the specified length and characters set. + * + * For a cryptographically random (but a little bit slower) use RandomStringWithAlphabet instead. + */ + (length: number, alphabet: string): string + } + interface randomStringByRegex { + /** + * RandomStringByRegex generates a random string matching the regex pattern. + * If optFlags is not set, fallbacks to [syntax.Perl]. + * + * NB! While the source of the randomness comes from [crypto/rand] this method + * is not recommended to be used on its own in critical secure contexts because + * the generated length could vary too much on the used pattern and may not be + * as secure as simply calling [security.RandomString]. + * If you still insist on using it for such purposes, consider at least + * a large enough minimum length for the generated string, e.g. `[a-z0-9]{30}`. + * + * This function is inspired by github.com/pipe01/revregexp, github.com/lucasjones/reggen and other similar packages. + */ + (pattern: string, ...optFlags: syntax.Flags[]): string } } @@ -5224,6 +5287,13 @@ namespace filesystem { originalName: string size: number } + interface File { + /** + * AsMap implements [core.mapExtractor] and returns a value suitable + * to be used in an API rule expression. + */ + asMap(): _TygojaDict + } interface newFileFromPath { /** * NewFileFromPath creates a new File instance from the provided local file path. @@ -5242,9 +5312,9 @@ namespace filesystem { */ (mh: multipart.FileHeader): (File) } - interface newFileFromUrl { + interface newFileFromURL { /** - * NewFileFromUrl creates a new File from the provided url by + * NewFileFromURL creates a new File from the provided url by * downloading the resource and load it as BytesReader. * * Example @@ -5253,7 +5323,7 @@ namespace filesystem { * ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) * defer cancel() * - * file, err := filesystem.NewFileFromUrl(ctx, "https://example.com/image.png") + * file, err := filesystem.NewFileFromURL(ctx, "https://example.com/image.png") * ``` */ (ctx: context.Context, url: string): (File) @@ -5294,8 +5364,8 @@ namespace filesystem { */ open(): io.ReadSeekCloser } - type _subazlvf = bytes.Reader - interface bytesReadSeekCloser extends _subazlvf { + type _seMetxv = bytes.Reader + interface bytesReadSeekCloser extends _seMetxv { } interface bytesReadSeekCloser { /** @@ -5303,6 +5373,16 @@ namespace filesystem { */ close(): void } + /** + * openFuncAsReader defines a FileReader from a bare Open function. + */ + interface openFuncAsReader {(): io.ReadSeekCloser } + interface openFuncAsReader { + /** + * Open implements the [filesystem.FileReader] interface. + */ + open(): io.ReadSeekCloser + } interface System { } interface newS3 { @@ -5342,22 +5422,50 @@ namespace filesystem { interface System { /** * Attributes returns the attributes for the file with fileKey path. + * + * If the file doesn't exist it returns ErrNotFound. */ attributes(fileKey: string): (blob.Attributes) } interface System { /** - * GetFile returns a file content reader for the given fileKey. + * GetReader returns a file content reader for the given fileKey. * - * NB! Make sure to call `Close()` after you are done working with it. + * NB! Make sure to call Close() on the file after you are done working with it. + * + * If the file doesn't exist returns ErrNotFound. */ - getFile(fileKey: string): (blob.Reader) + getReader(fileKey: string): (blob.Reader) } interface System { /** - * Copy copies the file stored at srcKey to dstKey. - * - * If dstKey file already exists, it is overwritten. + * Deprecated: Please use GetReader(fileKey) instead. + */ + getFile(fileKey: string): (blob.Reader) + } + interface System { + /** + * GetReuploadableFile constructs a new reuploadable File value + * from the associated fileKey blob.Reader. + * + * If preserveName is false then the returned File.Name will have + * a new randomly generated suffix, otherwise it will reuse the original one. + * + * This method could be useful in case you want to clone an existing + * Record file and assign it to a new Record (e.g. in a Record duplicate action). + * + * If you simply want to copy an existing file to a new location you + * could check the Copy(srcKey, dstKey) method. + */ + getReuploadableFile(fileKey: string, preserveName: boolean): (File) + } + interface System { + /** + * Copy copies the file stored at srcKey to dstKey. + * + * If srcKey file doesn't exist, it returns ErrNotFound. + * + * If dstKey file already exists, it is overwritten. */ copy(srcKey: string, dstKey: string): void } @@ -5375,7 +5483,7 @@ namespace filesystem { } interface System { /** - * UploadFile uploads the provided multipart file to the fileKey location. + * UploadFile uploads the provided File to the fileKey location. */ uploadFile(file: File, fileKey: string): void } @@ -5388,6 +5496,8 @@ namespace filesystem { interface System { /** * Delete deletes stored file at fileKey location. + * + * If the file doesn't exist returns ErrNotFound. */ delete(fileKey: string): void } @@ -5399,12 +5509,26 @@ namespace filesystem { */ deletePrefix(prefix: string): Array } + interface System { + /** + * Checks if the provided dir prefix doesn't have any files. + * + * A trailing slash will be appended to a non-empty dir string argument + * to ensure that the checked prefix is a "directory". + * + * Returns "false" in case the has at least one file, otherwise - "true". + */ + isEmptyDir(dir: string): boolean + } interface System { /** * Serve serves the file at fileKey location to an HTTP response. * * If the `download` query parameter is used the file will be always served for * download no matter of its type (aka. with "Content-Disposition: attachment"). + * + * Internally this method uses [http.ServeContent] so Range requests, + * If-Match, If-Unmodified-Since, etc. headers are handled transparently. */ serve(res: http.ResponseWriter, req: http.Request, fileKey: string, name: string): void } @@ -5423,9519 +5547,9329 @@ namespace filesystem { */ createThumb(originalKey: string, thumbKey: string, thumbSize: string): void } - // @ts-ignore - import v4 = signer - // @ts-ignore - import smithyhttp = http - interface ignoredHeadersKey { - } } /** - * Package tokens implements various user and admin tokens generation methods. + * Package exec runs external commands. It wraps os.StartProcess to make it + * easier to remap stdin and stdout, connect I/O with pipes, and do other + * adjustments. + * + * Unlike the "system" library call from C and other languages, the + * os/exec package intentionally does not invoke the system shell and + * does not expand any glob patterns or handle other expansions, + * pipelines, or redirections typically done by shells. The package + * behaves more like C's "exec" family of functions. To expand glob + * patterns, either call the shell directly, taking care to escape any + * dangerous input, or use the [path/filepath] package's Glob function. + * To expand environment variables, use package os's ExpandEnv. + * + * Note that the examples in this package assume a Unix system. + * They may not run on Windows, and they do not run in the Go Playground + * used by golang.org and godoc.org. + * + * # Executables in the current directory + * + * The functions [Command] and [LookPath] look for a program + * in the directories listed in the current path, following the + * conventions of the host operating system. + * Operating systems have for decades included the current + * directory in this search, sometimes implicitly and sometimes + * configured explicitly that way by default. + * Modern practice is that including the current directory + * is usually unexpected and often leads to security problems. + * + * To avoid those security problems, as of Go 1.19, this package will not resolve a program + * using an implicit or explicit path entry relative to the current directory. + * That is, if you run [LookPath]("go"), it will not successfully return + * ./go on Unix nor .\go.exe on Windows, no matter how the path is configured. + * Instead, if the usual path algorithms would result in that answer, + * these functions return an error err satisfying [errors.Is](err, [ErrDot]). + * + * For example, consider these two program snippets: + * + * ``` + * path, err := exec.LookPath("prog") + * if err != nil { + * log.Fatal(err) + * } + * use(path) + * ``` + * + * and + * + * ``` + * cmd := exec.Command("prog") + * if err := cmd.Run(); err != nil { + * log.Fatal(err) + * } + * ``` + * + * These will not find and run ./prog or .\prog.exe, + * no matter how the current path is configured. + * + * Code that always wants to run a program from the current directory + * can be rewritten to say "./prog" instead of "prog". + * + * Code that insists on including results from relative path entries + * can instead override the error using an errors.Is check: + * + * ``` + * path, err := exec.LookPath("prog") + * if errors.Is(err, exec.ErrDot) { + * err = nil + * } + * if err != nil { + * log.Fatal(err) + * } + * use(path) + * ``` + * + * and + * + * ``` + * cmd := exec.Command("prog") + * if errors.Is(cmd.Err, exec.ErrDot) { + * cmd.Err = nil + * } + * if err := cmd.Run(); err != nil { + * log.Fatal(err) + * } + * ``` + * + * Setting the environment variable GODEBUG=execerrdot=0 + * disables generation of ErrDot entirely, temporarily restoring the pre-Go 1.19 + * behavior for programs that are unable to apply more targeted fixes. + * A future version of Go may remove support for this variable. + * + * Before adding such overrides, make sure you understand the + * security implications of doing so. + * See https://go.dev/blog/path-security for more information. */ -namespace tokens { - interface newAdminAuthToken { - /** - * NewAdminAuthToken generates and returns a new admin authentication token. - */ - (app: CoreApp, admin: models.Admin): string - } - interface newAdminResetPasswordToken { - /** - * NewAdminResetPasswordToken generates and returns a new admin password reset request token. - */ - (app: CoreApp, admin: models.Admin): string - } - interface newAdminFileToken { - /** - * NewAdminFileToken generates and returns a new admin private file access token. - */ - (app: CoreApp, admin: models.Admin): string - } - interface newRecordAuthToken { +namespace exec { + interface command { /** - * NewRecordAuthToken generates and returns a new auth record authentication token. + * Command returns the [Cmd] struct to execute the named program with + * the given arguments. + * + * It sets only the Path and Args in the returned structure. + * + * If name contains no path separators, Command uses [LookPath] to + * resolve name to a complete path if possible. Otherwise it uses name + * directly as Path. + * + * The returned Cmd's Args field is constructed from the command name + * followed by the elements of arg, so arg should not include the + * command name itself. For example, Command("echo", "hello"). + * Args[0] is always name, not the possibly resolved Path. + * + * On Windows, processes receive the whole command line as a single string + * and do their own parsing. Command combines and quotes Args into a command + * line string with an algorithm compatible with applications using + * CommandLineToArgvW (which is the most common way). Notable exceptions are + * msiexec.exe and cmd.exe (and thus, all batch files), which have a different + * unquoting algorithm. In these or other similar cases, you can do the + * quoting yourself and provide the full command line in SysProcAttr.CmdLine, + * leaving Args empty. */ - (app: CoreApp, record: models.Record): string + (name: string, ...arg: string[]): (Cmd) } - interface newRecordVerifyToken { +} + +/** + * Package core is the backbone of PocketBase. + * + * It defines the main PocketBase App interface and its base implementation. + */ +namespace core { + /** + * App defines the main PocketBase app interface. + * + * Note that the interface is not intended to be implemented manually by users + * and instead they should use core.BaseApp (either directly or as embedded field in a custom struct). + * + * This interface exists to make testing easier and to allow users to + * create common and pluggable helpers and methods that doesn't rely + * on a specific wrapped app struct (hence the large interface size). + */ + interface App { + [key:string]: any; /** - * NewRecordVerifyToken generates and returns a new record verification token. + * UnsafeWithoutHooks returns a shallow copy of the current app WITHOUT any registered hooks. + * + * NB! Note that using the returned app instance may cause data integrity errors + * since the Record validations and data normalizations (including files uploads) + * rely on the app hooks to work. */ - (app: CoreApp, record: models.Record): string - } - interface newRecordResetPasswordToken { + unsafeWithoutHooks(): App /** - * NewRecordResetPasswordToken generates and returns a new auth record password reset request token. + * Logger returns the default app logger. + * + * If the application is not bootstrapped yet, fallbacks to slog.Default(). */ - (app: CoreApp, record: models.Record): string - } - interface newRecordChangeEmailToken { + logger(): (slog.Logger) /** - * NewRecordChangeEmailToken generates and returns a new auth record change email request token. + * IsBootstrapped checks if the application was initialized + * (aka. whether Bootstrap() was called). */ - (app: CoreApp, record: models.Record, newEmail: string): string - } - interface newRecordFileToken { + isBootstrapped(): boolean /** - * NewRecordFileToken generates and returns a new record private file access token. + * IsTransactional checks if the current app instance is part of a transaction. */ - (app: CoreApp, record: models.Record): string - } -} - -/** - * Package mails implements various helper methods for sending user and admin - * emails like forgotten password, verification, etc. - */ -namespace mails { - interface sendAdminPasswordReset { + isTransactional(): boolean /** - * SendAdminPasswordReset sends a password reset request email to the specified admin. + * TxInfo returns the transaction associated with the current app instance (if any). + * + * Could be used if you want to execute indirectly a function after + * the related app transaction completes using `app.TxInfo().OnAfterFunc(callback)`. */ - (app: CoreApp, admin: models.Admin): void - } - interface sendRecordPasswordLoginAlert { + txInfo(): (TxAppInfo) /** - * @todo remove after the refactoring + * Bootstrap initializes the application + * (aka. create data dir, open db connections, load settings, etc.). * - * SendRecordPasswordLoginAlert sends a OAuth2 password login alert to the specified auth record. + * It will call ResetBootstrapState() if the application was already bootstrapped. */ - (app: CoreApp, authRecord: models.Record, ...providerNames: string[]): void - } - interface sendRecordPasswordReset { + bootstrap(): void /** - * SendRecordPasswordReset sends a password reset request email to the specified user. + * ResetBootstrapState releases the initialized core app resources + * (closing db connections, stopping cron ticker, etc.). */ - (app: CoreApp, authRecord: models.Record): void - } - interface sendRecordVerification { + resetBootstrapState(): void /** - * SendRecordVerification sends a verification request email to the specified user. + * DataDir returns the app data directory path. */ - (app: CoreApp, authRecord: models.Record): void - } - interface sendRecordChangeEmail { + dataDir(): string /** - * SendRecordChangeEmail sends a change email confirmation email to the specified user. + * EncryptionEnv returns the name of the app secret env key + * (currently used primarily for optional settings encryption but this may change in the future). */ - (app: CoreApp, record: models.Record, newEmail: string): void - } -} - -namespace middleware { - interface bodyLimit { + encryptionEnv(): string /** - * BodyLimit returns a BodyLimit middleware. + * IsDev returns whether the app is in dev mode. * - * BodyLimit middleware sets the maximum allowed size for a request body, if the size exceeds the configured limit, it - * sends "413 - Request Entity Too Large" response. The BodyLimit is determined based on both `Content-Length` request - * header and actual content read, which makes it super secure. + * When enabled logs, executed sql statements, etc. are printed to the stderr. */ - (limitBytes: number): echo.MiddlewareFunc - } - interface gzip { + isDev(): boolean /** - * Gzip returns a middleware which compresses HTTP response using gzip compression scheme. + * Settings returns the loaded app settings. */ - (): echo.MiddlewareFunc - } -} - -/** - * Package models implements various services used for request data - * validation and applying changes to existing DB models through the app Dao. - */ -namespace forms { - // @ts-ignore - import validation = ozzo_validation - /** - * AdminLogin is an admin email/pass login form. - */ - interface AdminLogin { - identity: string - password: string - } - interface newAdminLogin { + settings(): (Settings) /** - * NewAdminLogin creates a new [AdminLogin] form initialized with - * the provided [CoreApp] instance. - * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * Store returns the app runtime store. */ - (app: CoreApp): (AdminLogin) - } - interface AdminLogin { + store(): (store.Store) /** - * SetDao replaces the default form Dao instance with the provided one. + * Cron returns the app cron instance. */ - setDao(dao: daos.Dao): void - } - interface AdminLogin { + cron(): (cron.Cron) /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * SubscriptionsBroker returns the app realtime subscriptions broker instance. */ - validate(): void - } - interface AdminLogin { + subscriptionsBroker(): (subscriptions.Broker) /** - * Submit validates and submits the admin form. - * On success returns the authorized admin model. - * - * You can optionally provide a list of InterceptorFunc to - * further modify the form behavior before persisting it. + * NewMailClient creates and returns a new SMTP or Sendmail client + * based on the current app settings. */ - submit(...interceptors: InterceptorFunc[]): (models.Admin) - } - /** - * AdminPasswordResetConfirm is an admin password reset confirmation form. - */ - interface AdminPasswordResetConfirm { - token: string - password: string - passwordConfirm: string - } - interface newAdminPasswordResetConfirm { + newMailClient(): mailer.Mailer /** - * NewAdminPasswordResetConfirm creates a new [AdminPasswordResetConfirm] - * form initialized with from the provided [CoreApp] instance. + * NewFilesystem creates a new local or S3 filesystem instance + * for managing regular app files (ex. record uploads) + * based on the current app settings. * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * NB! Make sure to call Close() on the returned result + * after you are done working with it. */ - (app: CoreApp): (AdminPasswordResetConfirm) - } - interface AdminPasswordResetConfirm { + newFilesystem(): (filesystem.System) /** - * SetDao replaces the form Dao instance with the provided one. + * NewBackupsFilesystem creates a new local or S3 filesystem instance + * for managing app backups based on the current app settings. * - * This is useful if you want to use a specific transaction Dao instance - * instead of the default app.Dao(). + * NB! Make sure to call Close() on the returned result + * after you are done working with it. */ - setDao(dao: daos.Dao): void - } - interface AdminPasswordResetConfirm { + newBackupsFilesystem(): (filesystem.System) /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * ReloadSettings reinitializes and reloads the stored application settings. */ - validate(): void - } - interface AdminPasswordResetConfirm { + reloadSettings(): void /** - * Submit validates and submits the admin password reset confirmation form. - * On success returns the updated admin model associated to `form.Token`. + * CreateBackup creates a new backup of the current app pb_data directory. * - * You can optionally provide a list of InterceptorFunc to further - * modify the form behavior before persisting it. - */ - submit(...interceptors: InterceptorFunc[]): (models.Admin) - } - /** - * AdminPasswordResetRequest is an admin password reset request form. - */ - interface AdminPasswordResetRequest { - email: string - } - interface newAdminPasswordResetRequest { - /** - * NewAdminPasswordResetRequest creates a new [AdminPasswordResetRequest] - * form initialized with from the provided [CoreApp] instance. + * Backups can be stored on S3 if it is configured in app.Settings().Backups. * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. - */ - (app: CoreApp): (AdminPasswordResetRequest) - } - interface AdminPasswordResetRequest { - /** - * SetDao replaces the default form Dao instance with the provided one. + * Please refer to the godoc of the specific CoreApp implementation + * for details on the backup procedures. */ - setDao(dao: daos.Dao): void - } - interface AdminPasswordResetRequest { + createBackup(ctx: context.Context, name: string): void /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * RestoreBackup restores the backup with the specified name and restarts + * the current running application process. + * + * The safely perform the restore it is recommended to have free disk space + * for at least 2x the size of the restored pb_data backup. + * + * Please refer to the godoc of the specific CoreApp implementation + * for details on the restore procedures. * - * This method doesn't verify that admin with `form.Email` exists (this is done on Submit). + * NB! This feature is experimental and currently is expected to work only on UNIX based systems. */ - validate(): void - } - interface AdminPasswordResetRequest { + restoreBackup(ctx: context.Context, name: string): void /** - * Submit validates and submits the form. - * On success sends a password reset email to the `form.Email` admin. + * Restart restarts (aka. replaces) the current running application process. * - * You can optionally provide a list of InterceptorFunc to further - * modify the form behavior before persisting it. + * NB! It relies on execve which is supported only on UNIX based systems. */ - submit(...interceptors: InterceptorFunc[]): void - } - /** - * AdminUpsert is a [models.Admin] upsert (create/update) form. - */ - interface AdminUpsert { - id: string - avatar: number - email: string - password: string - passwordConfirm: string - } - interface newAdminUpsert { + restart(): void /** - * NewAdminUpsert creates a new [AdminUpsert] form with initializer - * config created from the provided [CoreApp] and [models.Admin] instances - * (for create you could pass a pointer to an empty Admin - `&models.Admin{}`). - * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * RunSystemMigrations applies all new migrations registered in the [core.SystemMigrations] list. */ - (app: CoreApp, admin: models.Admin): (AdminUpsert) - } - interface AdminUpsert { + runSystemMigrations(): void /** - * SetDao replaces the default form Dao instance with the provided one. + * RunAppMigrations applies all new migrations registered in the [CoreAppMigrations] list. */ - setDao(dao: daos.Dao): void - } - interface AdminUpsert { + runAppMigrations(): void /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * RunAllMigrations applies all system and app migrations + * (aka. from both [core.SystemMigrations] and [CoreAppMigrations]). */ - validate(): void - } - interface AdminUpsert { + runAllMigrations(): void /** - * Submit validates the form and upserts the form admin model. + * DB returns the default app data.db builder instance. * - * You can optionally provide a list of InterceptorFunc to further - * modify the form behavior before persisting it. + * To minimize SQLITE_BUSY errors, it automatically routes the + * SELECT queries to the underlying concurrent db pool and everything else + * to the nonconcurrent one. + * + * For more finer control over the used connections pools you can + * call directly ConcurrentDB() or NonconcurrentDB(). */ - submit(...interceptors: InterceptorFunc[]): void - } - /** - * AppleClientSecretCreate is a form struct to generate a new Apple Client Secret. - * - * Reference: https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens - */ - interface AppleClientSecretCreate { + db(): dbx.Builder /** - * ClientId is the identifier of your app (aka. Service ID). + * ConcurrentDB returns the concurrent app data.db builder instance. + * + * This method is used mainly internally for executing db read + * operations in a concurrent/non-blocking manner. + * + * Most users should use simply DB() as it will automatically + * route the query execution to ConcurrentDB() or NonconcurrentDB(). + * + * In a transaction the ConcurrentDB() and NonconcurrentDB() refer to the same *dbx.TX instance. */ - clientId: string + concurrentDB(): dbx.Builder /** - * TeamId is a 10-character string associated with your developer account - * (usually could be found next to your name in the Apple Developer site). + * NonconcurrentDB returns the nonconcurrent app data.db builder instance. + * + * The returned db instance is limited only to a single open connection, + * meaning that it can process only 1 db operation at a time (other queries queue up). + * + * This method is used mainly internally and in the tests to execute write + * (save/delete) db operations as it helps with minimizing the SQLITE_BUSY errors. + * + * Most users should use simply DB() as it will automatically + * route the query execution to ConcurrentDB() or NonconcurrentDB(). + * + * In a transaction the ConcurrentDB() and NonconcurrentDB() refer to the same *dbx.TX instance. */ - teamId: string + nonconcurrentDB(): dbx.Builder /** - * KeyId is a 10-character key identifier generated for the "Sign in with Apple" - * private key associated with your developer account. + * AuxDB returns the app auxiliary.db builder instance. + * + * To minimize SQLITE_BUSY errors, it automatically routes the + * SELECT queries to the underlying concurrent db pool and everything else + * to the nonconcurrent one. + * + * For more finer control over the used connections pools you can + * call directly AuxConcurrentDB() or AuxNonconcurrentDB(). */ - keyId: string + auxDB(): dbx.Builder /** - * PrivateKey is the private key associated to your app. - * Usually wrapped within -----BEGIN PRIVATE KEY----- X -----END PRIVATE KEY-----. + * AuxConcurrentDB returns the concurrent app auxiliary.db builder instance. + * + * This method is used mainly internally for executing db read + * operations in a concurrent/non-blocking manner. + * + * Most users should use simply AuxDB() as it will automatically + * route the query execution to AuxConcurrentDB() or AuxNonconcurrentDB(). + * + * In a transaction the AuxConcurrentDB() and AuxNonconcurrentDB() refer to the same *dbx.TX instance. */ - privateKey: string + auxConcurrentDB(): dbx.Builder /** - * Duration specifies how long the generated JWT should be considered valid. - * The specified value must be in seconds and max 15777000 (~6months). + * AuxNonconcurrentDB returns the nonconcurrent app auxiliary.db builder instance. + * + * The returned db instance is limited only to a single open connection, + * meaning that it can process only 1 db operation at a time (other queries queue up). + * + * This method is used mainly internally and in the tests to execute write + * (save/delete) db operations as it helps with minimizing the SQLITE_BUSY errors. + * + * Most users should use simply AuxDB() as it will automatically + * route the query execution to AuxConcurrentDB() or AuxNonconcurrentDB(). + * + * In a transaction the AuxConcurrentDB() and AuxNonconcurrentDB() refer to the same *dbx.TX instance. */ - duration: number - } - interface newAppleClientSecretCreate { + auxNonconcurrentDB(): dbx.Builder /** - * NewAppleClientSecretCreate creates a new [AppleClientSecretCreate] form with initializer - * config created from the provided [CoreApp] instances. + * HasTable checks if a table (or view) with the provided name exists (case insensitive). + * in the data.db. */ - (app: CoreApp): (AppleClientSecretCreate) - } - interface AppleClientSecretCreate { + hasTable(tableName: string): boolean /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * AuxHasTable checks if a table (or view) with the provided name exists (case insensitive) + * in the auxiliary.db. */ - validate(): void - } - interface AppleClientSecretCreate { + auxHasTable(tableName: string): boolean /** - * Submit validates the form and returns a new Apple Client Secret JWT. + * TableColumns returns all column names of a single table by its name. */ - submit(): string - } - /** - * BackupCreate is a request form for creating a new app backup. - */ - interface BackupCreate { - name: string - } - interface newBackupCreate { + tableColumns(tableName: string): Array /** - * NewBackupCreate creates new BackupCreate request form. + * TableInfo returns the "table_info" pragma result for the specified table. */ - (app: CoreApp): (BackupCreate) - } - interface BackupCreate { + tableInfo(tableName: string): Array<(TableInfoRow | undefined)> /** - * SetContext replaces the default form context with the provided one. + * TableIndexes returns a name grouped map with all non empty index of the specified table. + * + * Note: This method doesn't return an error on nonexisting table. */ - setContext(ctx: context.Context): void - } - interface BackupCreate { + tableIndexes(tableName: string): _TygojaDict /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * DeleteTable drops the specified table. + * + * This method is a no-op if a table with the provided name doesn't exist. + * + * NB! Be aware that this method is vulnerable to SQL injection and the + * "tableName" argument must come only from trusted input! */ - validate(): void - } - interface BackupCreate { + deleteTable(tableName: string): void /** - * Submit validates the form and creates the app backup. + * DeleteView drops the specified view name. * - * You can optionally provide a list of InterceptorFunc to further - * modify the form behavior before creating the backup. + * This method is a no-op if a view with the provided name doesn't exist. + * + * NB! Be aware that this method is vulnerable to SQL injection and the + * "name" argument must come only from trusted input! */ - submit(...interceptors: InterceptorFunc[]): void - } - /** - * BackupUpload is a request form for uploading a new app backup. - */ - interface BackupUpload { - file?: filesystem.File - } - interface newBackupUpload { + deleteView(name: string): void /** - * NewBackupUpload creates new BackupUpload request form. + * SaveView creates (or updates already existing) persistent SQL view. + * + * NB! Be aware that this method is vulnerable to SQL injection and the + * "selectQuery" argument must come only from trusted input! */ - (app: CoreApp): (BackupUpload) - } - interface BackupUpload { + saveView(name: string, selectQuery: string): void /** - * SetContext replaces the default form upload context with the provided one. + * CreateViewFields creates a new FieldsList from the provided select query. + * + * There are some caveats: + * - The select query must have an "id" column. + * - Wildcard ("*") columns are not supported to avoid accidentally leaking sensitive data. */ - setContext(ctx: context.Context): void - } - interface BackupUpload { + createViewFields(selectQuery: string): FieldsList /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * FindRecordByViewFile returns the original Record of the provided view collection file. */ - validate(): void - } - interface BackupUpload { + findRecordByViewFile(viewCollectionModelOrIdentifier: any, fileFieldName: string, filename: string): (Record) /** - * Submit validates the form and upload the backup file. - * - * You can optionally provide a list of InterceptorFunc to further - * modify the form behavior before uploading the backup. + * Vacuum executes VACUUM on the data.db in order to reclaim unused data db disk space. */ - submit(...interceptors: InterceptorFunc[]): void - } - /** - * InterceptorNextFunc is a interceptor handler function. - * Usually used in combination with InterceptorFunc. - */ - interface InterceptorNextFunc {(t: T): void } - /** - * InterceptorFunc defines a single interceptor function that - * will execute the provided next func handler. - */ - interface InterceptorFunc {(next: InterceptorNextFunc): InterceptorNextFunc } - /** - * CollectionUpsert is a [models.Collection] upsert (create/update) form. - */ - interface CollectionUpsert { - id: string - type: string - name: string - system: boolean - schema: schema.Schema - indexes: types.JsonArray - listRule?: string - viewRule?: string - createRule?: string - updateRule?: string - deleteRule?: string - options: types.JsonMap - } - interface newCollectionUpsert { + vacuum(): void /** - * NewCollectionUpsert creates a new [CollectionUpsert] form with initializer - * config created from the provided [CoreApp] and [models.Collection] instances - * (for create you could pass a pointer to an empty Collection - `&models.Collection{}`). - * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * AuxVacuum executes VACUUM on the auxiliary.db in order to reclaim unused auxiliary db disk space. */ - (app: CoreApp, collection: models.Collection): (CollectionUpsert) - } - interface CollectionUpsert { + auxVacuum(): void /** - * SetDao replaces the default form Dao instance with the provided one. + * ModelQuery creates a new preconfigured select data.db query with preset + * SELECT, FROM and other common fields based on the provided model. */ - setDao(dao: daos.Dao): void - } - interface CollectionUpsert { + modelQuery(model: Model): (dbx.SelectQuery) /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * AuxModelQuery creates a new preconfigured select auxiliary.db query with preset + * SELECT, FROM and other common fields based on the provided model. */ - validate(): void - } - interface CollectionUpsert { + auxModelQuery(model: Model): (dbx.SelectQuery) /** - * Submit validates the form and upserts the form's Collection model. - * - * On success the related record table schema will be auto updated. - * - * You can optionally provide a list of InterceptorFunc to further - * modify the form behavior before persisting it. + * Delete deletes the specified model from the regular app database. */ - submit(...interceptors: InterceptorFunc[]): void - } - /** - * CollectionsImport is a form model to bulk import - * (create, replace and delete) collections from a user provided list. - */ - interface CollectionsImport { - collections: Array<(models.Collection | undefined)> - deleteMissing: boolean - } - interface newCollectionsImport { + delete(model: Model): void /** - * NewCollectionsImport creates a new [CollectionsImport] form with - * initialized with from the provided [CoreApp] instance. - * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * Delete deletes the specified model from the regular app database + * (the context could be used to limit the query execution). */ - (app: CoreApp): (CollectionsImport) - } - interface CollectionsImport { + deleteWithContext(ctx: context.Context, model: Model): void /** - * SetDao replaces the default form Dao instance with the provided one. + * AuxDelete deletes the specified model from the auxiliary database. */ - setDao(dao: daos.Dao): void - } - interface CollectionsImport { + auxDelete(model: Model): void /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * AuxDeleteWithContext deletes the specified model from the auxiliary database + * (the context could be used to limit the query execution). */ - validate(): void - } - interface CollectionsImport { + auxDeleteWithContext(ctx: context.Context, model: Model): void /** - * Submit applies the import, aka.: - * - imports the form collections (create or replace) - * - sync the collection changes with their related records table - * - ensures the integrity of the imported structure (aka. run validations for each collection) - * - if [form.DeleteMissing] is set, deletes all local collections that are not found in the imports list - * - * All operations are wrapped in a single transaction that are - * rollbacked on the first encountered error. + * Save validates and saves the specified model into the regular app database. * - * You can optionally provide a list of InterceptorFunc to further - * modify the form behavior before persisting it. + * If you don't want to run validations, use [App.SaveNoValidate()]. */ - submit(...interceptors: InterceptorFunc>[]): void - } - /** - * RealtimeSubscribe is a realtime subscriptions request form. - */ - interface RealtimeSubscribe { - clientId: string - subscriptions: Array - } - interface newRealtimeSubscribe { + save(model: Model): void /** - * NewRealtimeSubscribe creates new RealtimeSubscribe request form. + * SaveWithContext is the same as [App.Save()] but allows specifying a context to limit the db execution. + * + * If you don't want to run validations, use [App.SaveNoValidateWithContext()]. */ - (): (RealtimeSubscribe) - } - interface RealtimeSubscribe { + saveWithContext(ctx: context.Context, model: Model): void /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * SaveNoValidate saves the specified model into the regular app database without performing validations. + * + * If you want to also run validations before persisting, use [App.Save()]. */ - validate(): void - } - /** - * RecordEmailChangeConfirm is an auth record email change confirmation form. - */ - interface RecordEmailChangeConfirm { - token: string - password: string - } - interface newRecordEmailChangeConfirm { + saveNoValidate(model: Model): void /** - * NewRecordEmailChangeConfirm creates a new [RecordEmailChangeConfirm] form - * initialized with from the provided [CoreApp] and [models.Collection] instances. + * SaveNoValidateWithContext is the same as [App.SaveNoValidate()] + * but allows specifying a context to limit the db execution. * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * If you want to also run validations before persisting, use [App.SaveWithContext()]. */ - (app: CoreApp, collection: models.Collection): (RecordEmailChangeConfirm) - } - interface RecordEmailChangeConfirm { + saveNoValidateWithContext(ctx: context.Context, model: Model): void /** - * SetDao replaces the default form Dao instance with the provided one. + * AuxSave validates and saves the specified model into the auxiliary app database. + * + * If you don't want to run validations, use [App.AuxSaveNoValidate()]. */ - setDao(dao: daos.Dao): void - } - interface RecordEmailChangeConfirm { + auxSave(model: Model): void /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * AuxSaveWithContext is the same as [App.AuxSave()] but allows specifying a context to limit the db execution. + * + * If you don't want to run validations, use [App.AuxSaveNoValidateWithContext()]. */ - validate(): void - } - interface RecordEmailChangeConfirm { + auxSaveWithContext(ctx: context.Context, model: Model): void /** - * Submit validates and submits the auth record email change confirmation form. - * On success returns the updated auth record associated to `form.Token`. + * AuxSaveNoValidate saves the specified model into the auxiliary app database without performing validations. * - * You can optionally provide a list of InterceptorFunc to - * further modify the form behavior before persisting it. + * If you want to also run validations before persisting, use [App.AuxSave()]. */ - submit(...interceptors: InterceptorFunc[]): (models.Record) - } - /** - * RecordEmailChangeRequest is an auth record email change request form. - */ - interface RecordEmailChangeRequest { - newEmail: string - } - interface newRecordEmailChangeRequest { + auxSaveNoValidate(model: Model): void /** - * NewRecordEmailChangeRequest creates a new [RecordEmailChangeRequest] form - * initialized with from the provided [CoreApp] and [models.Record] instances. + * AuxSaveNoValidateWithContext is the same as [App.AuxSaveNoValidate()] + * but allows specifying a context to limit the db execution. * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * If you want to also run validations before persisting, use [App.AuxSaveWithContext()]. */ - (app: CoreApp, record: models.Record): (RecordEmailChangeRequest) - } - interface RecordEmailChangeRequest { + auxSaveNoValidateWithContext(ctx: context.Context, model: Model): void /** - * SetDao replaces the default form Dao instance with the provided one. + * Validate triggers the OnModelValidate hook for the specified model. */ - setDao(dao: daos.Dao): void - } - interface RecordEmailChangeRequest { + validate(model: Model): void /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * ValidateWithContext is the same as Validate but allows specifying the ModelEvent context. */ - validate(): void - } - interface RecordEmailChangeRequest { + validateWithContext(ctx: context.Context, model: Model): void /** - * Submit validates and sends the change email request. + * RunInTransaction wraps fn into a transaction for the regular app database. * - * You can optionally provide a list of InterceptorFunc to - * further modify the form behavior before persisting it. + * It is safe to nest RunInTransaction calls as long as you use the callback's txApp. */ - submit(...interceptors: InterceptorFunc[]): void - } - /** - * RecordOAuth2LoginData defines the OA - */ - interface RecordOAuth2LoginData { - externalAuth?: models.ExternalAuth - record?: models.Record - oAuth2User?: auth.AuthUser - providerClient: auth.Provider - } - /** - * BeforeOAuth2RecordCreateFunc defines a callback function that will - * be called before OAuth2 new Record creation. - */ - interface BeforeOAuth2RecordCreateFunc {(createForm: RecordUpsert, authRecord: models.Record, authUser: auth.AuthUser): void } - /** - * RecordOAuth2Login is an auth record OAuth2 login form. - */ - interface RecordOAuth2Login { + runInTransaction(fn: (txApp: App) => void): void /** - * The name of the OAuth2 client provider (eg. "google") + * AuxRunInTransaction wraps fn into a transaction for the auxiliary app database. + * + * It is safe to nest RunInTransaction calls as long as you use the callback's txApp. */ - provider: string + auxRunInTransaction(fn: (txApp: App) => void): void /** - * The authorization code returned from the initial request. + * LogQuery returns a new Log select query. */ - code: string + logQuery(): (dbx.SelectQuery) /** - * The optional PKCE code verifier as part of the code_challenge sent with the initial request. + * FindLogById finds a single Log entry by its id. */ - codeVerifier: string + findLogById(id: string): (Log) /** - * The redirect url sent with the initial request. + * LogsStatsItem returns hourly grouped logs statistics. */ - redirectUrl: string + logsStats(expr: dbx.Expression): Array<(LogsStatsItem | undefined)> /** - * Additional data that will be used for creating a new auth record - * if an existing OAuth2 account doesn't exist. + * DeleteOldLogs delete all logs that are created before createdBefore. */ - createData: _TygojaDict - } - interface newRecordOAuth2Login { + deleteOldLogs(createdBefore: time.Time): void + /** + * CollectionQuery returns a new Collection select query. + */ + collectionQuery(): (dbx.SelectQuery) /** - * NewRecordOAuth2Login creates a new [RecordOAuth2Login] form with - * initialized with from the provided [CoreApp] instance. + * FindCollections finds all collections by the given type(s). + * + * If collectionTypes is not set, it returns all collections. + * + * Example: * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * ``` + * app.FindAllCollections() // all collections + * app.FindAllCollections("auth", "view") // only auth and view collections + * ``` */ - (app: CoreApp, collection: models.Collection, optAuthRecord: models.Record): (RecordOAuth2Login) - } - interface RecordOAuth2Login { + findAllCollections(...collectionTypes: string[]): Array<(Collection | undefined)> /** - * SetDao replaces the default form Dao instance with the provided one. + * ReloadCachedCollections fetches all collections and caches them into the app store. */ - setDao(dao: daos.Dao): void - } - interface RecordOAuth2Login { + reloadCachedCollections(): void /** - * SetBeforeNewRecordCreateFunc sets a before OAuth2 record create callback handler. + * FindCollectionByNameOrId finds a single collection by its name (case insensitive) or id.s */ - setBeforeNewRecordCreateFunc(f: BeforeOAuth2RecordCreateFunc): void - } - interface RecordOAuth2Login { + findCollectionByNameOrId(nameOrId: string): (Collection) /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * FindCachedCollectionByNameOrId is similar to [App.FindCollectionByNameOrId] + * but retrieves the Collection from the app cache instead of making a db call. + * + * NB! This method is suitable for read-only Collection operations. + * + * Returns [sql.ErrNoRows] if no Collection is found for consistency + * with the [App.FindCollectionByNameOrId] method. + * + * If you plan making changes to the returned Collection model, + * use [App.FindCollectionByNameOrId] instead. + * + * Caveats: + * + * ``` + * - The returned Collection should be used only for read-only operations. + * Avoid directly modifying the returned cached Collection as it will affect + * the global cached value even if you don't persist the changes in the database! + * - If you are updating a Collection in a transaction and then call this method before commit, + * it'll return the cached Collection state and not the one from the uncommitted transaction. + * - The cache is automatically updated on collections db change (create/update/delete). + * To manually reload the cache you can call [App.ReloadCachedCollections] + * ``` */ - validate(): void - } - interface RecordOAuth2Login { + findCachedCollectionByNameOrId(nameOrId: string): (Collection) + /** + * FindCollectionReferences returns information for all relation + * fields referencing the provided collection. + * + * If the provided collection has reference to itself then it will be + * also included in the result. To exclude it, pass the collection id + * as the excludeIds argument. + */ + findCollectionReferences(collection: Collection, ...excludeIds: string[]): _TygojaDict /** - * Submit validates and submits the form. + * FindCachedCollectionReferences is similar to [App.FindCollectionReferences] + * but retrieves the Collection from the app cache instead of making a db call. + * + * NB! This method is suitable for read-only Collection operations. * - * If an auth record doesn't exist, it will make an attempt to create it - * based on the fetched OAuth2 profile data via a local [RecordUpsert] form. - * You can intercept/modify the Record create form with [form.SetBeforeNewRecordCreateFunc()]. + * If you plan making changes to the returned Collection model, + * use [App.FindCollectionReferences] instead. * - * You can also optionally provide a list of InterceptorFunc to - * further modify the form behavior before persisting it. + * Caveats: * - * On success returns the authorized record model and the fetched provider's data. + * ``` + * - The returned Collection should be used only for read-only operations. + * Avoid directly modifying the returned cached Collection as it will affect + * the global cached value even if you don't persist the changes in the database! + * - If you are updating a Collection in a transaction and then call this method before commit, + * it'll return the cached Collection state and not the one from the uncommitted transaction. + * - The cache is automatically updated on collections db change (create/update/delete). + * To manually reload the cache you can call [App.ReloadCachedCollections]. + * ``` */ - submit(...interceptors: InterceptorFunc[]): [(models.Record), (auth.AuthUser)] - } - /** - * RecordPasswordLogin is record username/email + password login form. - */ - interface RecordPasswordLogin { - identity: string - password: string - } - interface newRecordPasswordLogin { + findCachedCollectionReferences(collection: Collection, ...excludeIds: string[]): _TygojaDict /** - * NewRecordPasswordLogin creates a new [RecordPasswordLogin] form initialized - * with from the provided [CoreApp] and [models.Collection] instance. + * IsCollectionNameUnique checks that there is no existing collection + * with the provided name (case insensitive!). * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * Note: case insensitive check because the name is used also as + * table name for the records. */ - (app: CoreApp, collection: models.Collection): (RecordPasswordLogin) - } - interface RecordPasswordLogin { + isCollectionNameUnique(name: string, ...excludeIds: string[]): boolean /** - * SetDao replaces the default form Dao instance with the provided one. + * TruncateCollection deletes all records associated with the provided collection. + * + * The truncate operation is executed in a single transaction, + * aka. either everything is deleted or none. + * + * Note that this method will also trigger the records related + * cascade and file delete actions. */ - setDao(dao: daos.Dao): void - } - interface RecordPasswordLogin { + truncateCollection(collection: Collection): void /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * ImportCollections imports the provided collections data in a single transaction. + * + * For existing matching collections, the imported data is unmarshaled on top of the existing model. + * + * NB! If deleteMissing is true, ALL NON-SYSTEM COLLECTIONS AND SCHEMA FIELDS, + * that are not present in the imported configuration, WILL BE DELETED + * (this includes their related records data). */ - validate(): void - } - interface RecordPasswordLogin { + importCollections(toImport: Array<_TygojaDict>, deleteMissing: boolean): void /** - * Submit validates and submits the form. - * On success returns the authorized record model. - * - * You can optionally provide a list of InterceptorFunc to - * further modify the form behavior before persisting it. + * ImportCollectionsByMarshaledJSON is the same as [ImportCollections] + * but accept marshaled json array as import data (usually used for the autogenerated snapshots). */ - submit(...interceptors: InterceptorFunc[]): (models.Record) - } - /** - * RecordPasswordResetConfirm is an auth record password reset confirmation form. - */ - interface RecordPasswordResetConfirm { - token: string - password: string - passwordConfirm: string - } - interface newRecordPasswordResetConfirm { + importCollectionsByMarshaledJSON(rawSliceOfMaps: string|Array, deleteMissing: boolean): void /** - * NewRecordPasswordResetConfirm creates a new [RecordPasswordResetConfirm] - * form initialized with from the provided [CoreApp] instance. + * SyncRecordTableSchema compares the two provided collections + * and applies the necessary related record table changes. * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * If oldCollection is null, then only newCollection is used to create the record table. + * + * This method is automatically invoked as part of a collection create/update/delete operation. */ - (app: CoreApp, collection: models.Collection): (RecordPasswordResetConfirm) - } - interface RecordPasswordResetConfirm { + syncRecordTableSchema(newCollection: Collection, oldCollection: Collection): void /** - * SetDao replaces the default form Dao instance with the provided one. + * FindAllExternalAuthsByRecord returns all ExternalAuth models + * linked to the provided auth record. */ - setDao(dao: daos.Dao): void - } - interface RecordPasswordResetConfirm { + findAllExternalAuthsByRecord(authRecord: Record): Array<(ExternalAuth | undefined)> /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * FindAllExternalAuthsByCollection returns all ExternalAuth models + * linked to the provided auth collection. */ - validate(): void - } - interface RecordPasswordResetConfirm { + findAllExternalAuthsByCollection(collection: Collection): Array<(ExternalAuth | undefined)> /** - * Submit validates and submits the form. - * On success returns the updated auth record associated to `form.Token`. - * - * You can optionally provide a list of InterceptorFunc to further - * modify the form behavior before persisting it. + * FindFirstExternalAuthByExpr returns the first available (the most recent created) + * ExternalAuth model that satisfies the non-nil expression. */ - submit(...interceptors: InterceptorFunc[]): (models.Record) - } - /** - * RecordPasswordResetRequest is an auth record reset password request form. - */ - interface RecordPasswordResetRequest { - email: string - } - interface newRecordPasswordResetRequest { + findFirstExternalAuthByExpr(expr: dbx.Expression): (ExternalAuth) /** - * NewRecordPasswordResetRequest creates a new [RecordPasswordResetRequest] - * form initialized with from the provided [CoreApp] instance. - * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * FindAllMFAsByRecord returns all MFA models linked to the provided auth record. */ - (app: CoreApp, collection: models.Collection): (RecordPasswordResetRequest) - } - interface RecordPasswordResetRequest { + findAllMFAsByRecord(authRecord: Record): Array<(MFA | undefined)> /** - * SetDao replaces the default form Dao instance with the provided one. + * FindAllMFAsByCollection returns all MFA models linked to the provided collection. */ - setDao(dao: daos.Dao): void - } - interface RecordPasswordResetRequest { + findAllMFAsByCollection(collection: Collection): Array<(MFA | undefined)> /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. - * - * This method doesn't check whether auth record with `form.Email` exists (this is done on Submit). + * FindMFAById returns a single MFA model by its id. */ - validate(): void - } - interface RecordPasswordResetRequest { + findMFAById(id: string): (MFA) /** - * Submit validates and submits the form. - * On success, sends a password reset email to the `form.Email` auth record. + * DeleteAllMFAsByRecord deletes all MFA models associated with the provided record. * - * You can optionally provide a list of InterceptorFunc to further - * modify the form behavior before persisting it. + * Returns a combined error with the failed deletes. */ - submit(...interceptors: InterceptorFunc[]): void - } - /** - * RecordUpsert is a [models.Record] upsert (create/update) form. - */ - interface RecordUpsert { + deleteAllMFAsByRecord(authRecord: Record): void /** - * base model fields + * DeleteExpiredMFAs deletes the expired MFAs for all auth collections. */ - id: string + deleteExpiredMFAs(): void /** - * auth collection fields - * --- + * FindAllOTPsByRecord returns all OTP models linked to the provided auth record. */ - username: string - email: string - emailVisibility: boolean - verified: boolean - password: string - passwordConfirm: string - oldPassword: string - } - interface newRecordUpsert { + findAllOTPsByRecord(authRecord: Record): Array<(OTP | undefined)> + /** + * FindAllOTPsByCollection returns all OTP models linked to the provided collection. + */ + findAllOTPsByCollection(collection: Collection): Array<(OTP | undefined)> /** - * NewRecordUpsert creates a new [RecordUpsert] form with initializer - * config created from the provided [CoreApp] and [models.Record] instances - * (for create you could pass a pointer to an empty Record - models.NewRecord(collection)). + * FindOTPById returns a single OTP model by its id. + */ + findOTPById(id: string): (OTP) + /** + * DeleteAllOTPsByRecord deletes all OTP models associated with the provided record. * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * Returns a combined error with the failed deletes. */ - (app: CoreApp, record: models.Record): (RecordUpsert) - } - interface RecordUpsert { + deleteAllOTPsByRecord(authRecord: Record): void /** - * Data returns the loaded form's data. + * DeleteExpiredOTPs deletes the expired OTPs for all auth collections. */ - data(): _TygojaDict - } - interface RecordUpsert { + deleteExpiredOTPs(): void /** - * SetFullManageAccess sets the manageAccess bool flag of the current - * form to enable/disable directly changing some system record fields - * (often used with auth collection records). + * FindAllAuthOriginsByRecord returns all AuthOrigin models linked to the provided auth record (in DESC order). */ - setFullManageAccess(fullManageAccess: boolean): void - } - interface RecordUpsert { + findAllAuthOriginsByRecord(authRecord: Record): Array<(AuthOrigin | undefined)> /** - * SetDao replaces the default form Dao instance with the provided one. + * FindAllAuthOriginsByCollection returns all AuthOrigin models linked to the provided collection (in DESC order). */ - setDao(dao: daos.Dao): void - } - interface RecordUpsert { + findAllAuthOriginsByCollection(collection: Collection): Array<(AuthOrigin | undefined)> + /** + * FindAuthOriginById returns a single AuthOrigin model by its id. + */ + findAuthOriginById(id: string): (AuthOrigin) /** - * LoadRequest extracts the json or multipart/form-data request data - * and lods it into the form. + * FindAuthOriginByRecordAndFingerprint returns a single AuthOrigin model + * by its authRecord relation and fingerprint. + */ + findAuthOriginByRecordAndFingerprint(authRecord: Record, fingerprint: string): (AuthOrigin) + /** + * DeleteAllAuthOriginsByRecord deletes all AuthOrigin models associated with the provided record. * - * File upload is supported only via multipart/form-data. + * Returns a combined error with the failed deletes. */ - loadRequest(r: http.Request, keyPrefix: string): void - } - interface RecordUpsert { + deleteAllAuthOriginsByRecord(authRecord: Record): void /** - * FilesToUpload returns the parsed request files ready for upload. + * RecordQuery returns a new Record select query from a collection model, id or name. + * + * In case a collection id or name is provided and that collection doesn't + * actually exists, the generated query will be created with a cancelled context + * and will fail once an executor (Row(), One(), All(), etc.) is called. */ - filesToUpload(): _TygojaDict - } - interface RecordUpsert { + recordQuery(collectionModelOrIdentifier: any): (dbx.SelectQuery) /** - * FilesToUpload returns the parsed request filenames ready to be deleted. + * FindRecordById finds the Record model by its id. */ - filesToDelete(): Array - } - interface RecordUpsert { + findRecordById(collectionModelOrIdentifier: any, recordId: string, ...optFilters: ((q: dbx.SelectQuery) => void)[]): (Record) + /** + * FindRecordsByIds finds all records by the specified ids. + * If no records are found, returns an empty slice. + */ + findRecordsByIds(collectionModelOrIdentifier: any, recordIds: Array, ...optFilters: ((q: dbx.SelectQuery) => void)[]): Array<(Record | undefined)> /** - * AddFiles adds the provided file(s) to the specified file field. + * FindAllRecords finds all records matching specified db expressions. * - * If the file field is a SINGLE-value file field (aka. "Max Select = 1"), - * then the newly added file will REPLACE the existing one. - * In this case if you pass more than 1 files only the first one will be assigned. + * Returns all collection records if no expression is provided. * - * If the file field is a MULTI-value file field (aka. "Max Select > 1"), - * then the newly added file(s) will be APPENDED to the existing one(s). + * Returns an empty slice if no records are found. * - * Example + * Example: * * ``` - * f1, _ := filesystem.NewFileFromPath("/path/to/file1.txt") - * f2, _ := filesystem.NewFileFromPath("/path/to/file2.txt") - * form.AddFiles("documents", f1, f2) + * // no extra expressions + * app.FindAllRecords("example") + * + * // with extra expressions + * expr1 := dbx.HashExp{"email": "test@example.com"} + * expr2 := dbx.NewExp("LOWER(username) = {:username}", dbx.Params{"username": "test"}) + * app.FindAllRecords("example", expr1, expr2) * ``` */ - addFiles(key: string, ...files: (filesystem.File | undefined)[]): void - } - interface RecordUpsert { + findAllRecords(collectionModelOrIdentifier: any, ...exprs: dbx.Expression[]): Array<(Record | undefined)> + /** + * FindFirstRecordByData returns the first found record matching + * the provided key-value pair. + */ + findFirstRecordByData(collectionModelOrIdentifier: any, key: string, value: any): (Record) /** - * RemoveFiles removes a single or multiple file from the specified file field. + * FindRecordsByFilter returns limit number of records matching the + * provided string filter. * - * NB! If filesToDelete is not set it will remove all existing files - * assigned to the file field (including those assigned with AddFiles)! + * NB! Use the last "params" argument to bind untrusted user variables! * - * Example + * The filter argument is optional and can be empty string to target + * all available records. + * + * The sort argument is optional and can be empty string OR the same format + * used in the web APIs, ex. "-created,title". + * + * If the limit argument is <= 0, no limit is applied to the query and + * all matching records are returned. + * + * Returns an empty slice if no records are found. + * + * Example: * * ``` - * // mark only only 2 files for removal - * form.RemoveFiles("documents", "file1_aw4bdrvws6.txt", "file2_xwbs36bafv.txt") + * app.FindRecordsByFilter( + * "posts", + * "title ~ {:title} && visible = {:visible}", + * "-created", + * 10, + * 0, + * dbx.Params{"title": "lorem ipsum", "visible": true} + * ) + * ``` + */ + findRecordsByFilter(collectionModelOrIdentifier: any, filter: string, sort: string, limit: number, offset: number, ...params: dbx.Params[]): Array<(Record | undefined)> + /** + * FindFirstRecordByFilter returns the first available record matching the provided filter (if any). + * + * NB! Use the last params argument to bind untrusted user variables! + * + * Returns sql.ErrNoRows if no record is found. + * + * Example: * - * // mark all "documents" files for removal - * form.RemoveFiles("documents") + * ``` + * app.FindFirstRecordByFilter("posts", "") + * app.FindFirstRecordByFilter("posts", "slug={:slug} && status='public'", dbx.Params{"slug": "test"}) * ``` */ - removeFiles(key: string, ...toDelete: string[]): void - } - interface RecordUpsert { + findFirstRecordByFilter(collectionModelOrIdentifier: any, filter: string, ...params: dbx.Params[]): (Record) /** - * LoadData loads and normalizes the provided regular record data fields into the form. + * CountRecords returns the total number of records in a collection. */ - loadData(requestData: _TygojaDict): void - } - interface RecordUpsert { + countRecords(collectionModelOrIdentifier: any, ...exprs: dbx.Expression[]): number /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * FindAuthRecordByToken finds the auth record associated with the provided JWT + * (auth, file, verifyEmail, changeEmail, passwordReset types). + * + * Optionally specify a list of validTypes to check tokens only from those types. + * + * Returns an error if the JWT is invalid, expired or not associated to an auth collection record. */ - validate(): void - } - interface RecordUpsert { - validateAndFill(): void - } - interface RecordUpsert { + findAuthRecordByToken(token: string, ...validTypes: string[]): (Record) /** - * DrySubmit performs a form submit within a transaction and reverts it. - * For actual record persistence, check the `form.Submit()` method. + * FindAuthRecordByEmail finds the auth record associated with the provided email. * - * This method doesn't handle file uploads/deletes or trigger any app events! + * Returns an error if it is not an auth collection or the record is not found. */ - drySubmit(callback: (txDao: daos.Dao) => void): void - } - interface RecordUpsert { + findAuthRecordByEmail(collectionModelOrIdentifier: any, email: string): (Record) /** - * Submit validates the form and upserts the form Record model. + * CanAccessRecord checks if a record is allowed to be accessed by the + * specified requestInfo and accessRule. + * + * Rule and db checks are ignored in case requestInfo.Auth is a superuser. + * + * The returned error indicate that something unexpected happened during + * the check (eg. invalid rule or db query error). + * + * The method always return false on invalid rule or db query error. + * + * Example: + * + * ``` + * requestInfo, _ := e.RequestInfo() + * record, _ := app.FindRecordById("example", "RECORD_ID") + * rule := types.Pointer("@request.auth.id != '' || status = 'public'") + * // ... or use one of the record collection's rule, eg. record.Collection().ViewRule * - * You can optionally provide a list of InterceptorFunc to further - * modify the form behavior before persisting it. + * if ok, _ := app.CanAccessRecord(record, requestInfo, rule); ok { ... } + * ``` */ - submit(...interceptors: InterceptorFunc[]): void - } - /** - * RecordVerificationConfirm is an auth record email verification confirmation form. - */ - interface RecordVerificationConfirm { - token: string - } - interface newRecordVerificationConfirm { + canAccessRecord(record: Record, requestInfo: RequestInfo, accessRule: string): boolean /** - * NewRecordVerificationConfirm creates a new [RecordVerificationConfirm] - * form initialized with from the provided [CoreApp] instance. + * ExpandRecord expands the relations of a single Record model. + * + * If optFetchFunc is not set, then a default function will be used + * that returns all relation records. * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * Returns a map with the failed expand parameters and their errors. */ - (app: CoreApp, collection: models.Collection): (RecordVerificationConfirm) - } - interface RecordVerificationConfirm { + expandRecord(record: Record, expands: Array, optFetchFunc: ExpandFetchFunc): _TygojaDict /** - * SetDao replaces the default form Dao instance with the provided one. + * ExpandRecords expands the relations of the provided Record models list. + * + * If optFetchFunc is not set, then a default function will be used + * that returns all relation records. + * + * Returns a map with the failed expand parameters and their errors. */ - setDao(dao: daos.Dao): void - } - interface RecordVerificationConfirm { + expandRecords(records: Array<(Record | undefined)>, expands: Array, optFetchFunc: ExpandFetchFunc): _TygojaDict /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * OnBootstrap hook is triggered when initializing the main application + * resources (db, app settings, etc). */ - validate(): void - } - interface RecordVerificationConfirm { + onBootstrap(): (hook.Hook) /** - * Submit validates and submits the form. - * On success returns the verified auth record associated to `form.Token`. - * - * You can optionally provide a list of InterceptorFunc to further - * modify the form behavior before persisting it. + * OnServe hook is triggered when the app web server is started + * (after starting the TCP listener but before initializing the blocking serve task), + * allowing you to adjust its options and attach new routes or middlewares. */ - submit(...interceptors: InterceptorFunc[]): (models.Record) - } - /** - * RecordVerificationRequest is an auth record email verification request form. - */ - interface RecordVerificationRequest { - email: string - } - interface newRecordVerificationRequest { + onServe(): (hook.Hook) /** - * NewRecordVerificationRequest creates a new [RecordVerificationRequest] - * form initialized with from the provided [CoreApp] instance. + * OnTerminate hook is triggered when the app is in the process + * of being terminated (ex. on SIGTERM signal). * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * Note that the app could be terminated abruptly without awaiting the hook completion. */ - (app: CoreApp, collection: models.Collection): (RecordVerificationRequest) - } - interface RecordVerificationRequest { + onTerminate(): (hook.Hook) /** - * SetDao replaces the default form Dao instance with the provided one. + * OnBackupCreate hook is triggered on each [App.CreateBackup] call. */ - setDao(dao: daos.Dao): void - } - interface RecordVerificationRequest { + onBackupCreate(): (hook.Hook) /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * OnBackupRestore hook is triggered before app backup restore (aka. [App.RestoreBackup] call). * - * // This method doesn't verify that auth record with `form.Email` exists (this is done on Submit). + * Note that by default on success the application is restarted and the after state of the hook is ignored. */ - validate(): void - } - interface RecordVerificationRequest { + onBackupRestore(): (hook.Hook) /** - * Submit validates and sends a verification request email - * to the `form.Email` auth record. + * OnModelValidate is triggered every time when a model is being validated + * (e.g. triggered by App.Validate() or App.Save()). * - * You can optionally provide a list of InterceptorFunc to further - * modify the form behavior before persisting it. + * For convenience, if you want to listen to only the Record models + * events without doing manual type assertion, you can attach to the OnRecord* proxy hooks. + * + * If the optional "tags" list (Collection id/name, Model table name, etc.) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - submit(...interceptors: InterceptorFunc[]): void - } - /** - * SettingsUpsert is a [settings.Settings] upsert (create/update) form. - */ - type _subHPqgL = settings.Settings - interface SettingsUpsert extends _subHPqgL { - } - interface newSettingsUpsert { + onModelValidate(...tags: string[]): (hook.TaggedHook) /** - * NewSettingsUpsert creates a new [SettingsUpsert] form with initializer - * config created from the provided [CoreApp] instance. + * OnModelCreate is triggered every time when a new model is being created + * (e.g. triggered by App.Save()). + * + * Operations BEFORE the e.Next() execute before the model validation + * and the INSERT DB statement. * - * If you want to submit the form as part of a transaction, - * you can change the default Dao via [SetDao()]. + * Operations AFTER the e.Next() execute after the model validation + * and the INSERT DB statement. + * + * Note that successful execution doesn't guarantee that the model + * is persisted in the database since its wrapping transaction may + * not have been committed yet. + * If you want to listen to only the actual persisted events, you can + * bind to [OnModelAfterCreateSuccess] or [OnModelAfterCreateError] hooks. + * + * For convenience, if you want to listen to only the Record models + * events without doing manual type assertion, you can attach to the OnRecord* proxy hooks. + * + * If the optional "tags" list (Collection id/name, Model table name, etc.) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (app: CoreApp): (SettingsUpsert) - } - interface SettingsUpsert { + onModelCreate(...tags: string[]): (hook.TaggedHook) /** - * SetDao replaces the default form Dao instance with the provided one. + * OnModelCreateExecute is triggered after successful Model validation + * and right before the model INSERT DB statement execution. + * + * Usually it is triggered as part of the App.Save() in the following firing order: + * OnModelCreate { + * ``` + * -> OnModelValidate (skipped with App.SaveNoValidate()) + * -> OnModelCreateExecute + * ``` + * } + * + * Note that successful execution doesn't guarantee that the model + * is persisted in the database since its wrapping transaction may have been + * committed yet. + * If you want to listen to only the actual persisted events, + * you can bind to [OnModelAfterCreateSuccess] or [OnModelAfterCreateError] hooks. + * + * For convenience, if you want to listen to only the Record models + * events without doing manual type assertion, you can attach to the OnRecord* proxy hooks. + * + * If the optional "tags" list (Collection id/name, Model table name, etc.) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - setDao(dao: daos.Dao): void - } - interface SettingsUpsert { + onModelCreateExecute(...tags: string[]): (hook.TaggedHook) /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * OnModelAfterCreateSuccess is triggered after each successful + * Model DB create persistence. + * + * Note that when a Model is persisted as part of a transaction, + * this hook is delayed and executed only AFTER the transaction has been committed. + * This hook is NOT triggered in case the transaction rollbacks + * (aka. when the model wasn't persisted). + * + * For convenience, if you want to listen to only the Record models + * events without doing manual type assertion, you can attach to the OnRecord* proxy hooks. + * + * If the optional "tags" list (Collection id/name, Model table name, etc.) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - validate(): void - } - interface SettingsUpsert { + onModelAfterCreateSuccess(...tags: string[]): (hook.TaggedHook) /** - * Submit validates the form and upserts the loaded settings. + * OnModelAfterCreateError is triggered after each failed + * Model DB create persistence. + * + * Note that the execution of this hook is either immediate or delayed + * depending on the error: + * ``` + * - "immediate" on App.Save() failure + * - "delayed" on transaction rollback + * ``` * - * On success the app settings will be refreshed with the form ones. + * For convenience, if you want to listen to only the Record models + * events without doing manual type assertion, you can attach to the OnRecord* proxy hooks. * - * You can optionally provide a list of InterceptorFunc to further - * modify the form behavior before persisting it. + * If the optional "tags" list (Collection id/name, Model table name, etc.) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - submit(...interceptors: InterceptorFunc[]): void - } - /** - * TestEmailSend is a email template test request form. - */ - interface TestEmailSend { - template: string - email: string - } - interface newTestEmailSend { + onModelAfterCreateError(...tags: string[]): (hook.TaggedHook) /** - * NewTestEmailSend creates and initializes new TestEmailSend form. + * OnModelUpdate is triggered every time when a new model is being updated + * (e.g. triggered by App.Save()). + * + * Operations BEFORE the e.Next() execute before the model validation + * and the UPDATE DB statement. + * + * Operations AFTER the e.Next() execute after the model validation + * and the UPDATE DB statement. + * + * Note that successful execution doesn't guarantee that the model + * is persisted in the database since its wrapping transaction may + * not have been committed yet. + * If you want to listen to only the actual persisted events, you can + * bind to [OnModelAfterUpdateSuccess] or [OnModelAfterUpdateError] hooks. + * + * For convenience, if you want to listen to only the Record models + * events without doing manual type assertion, you can attach to the OnRecord* proxy hooks. + * + * If the optional "tags" list (Collection id/name, Model table name, etc.) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (app: CoreApp): (TestEmailSend) - } - interface TestEmailSend { + onModelUpdate(...tags: string[]): (hook.TaggedHook) /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * OnModelUpdateExecute is triggered after successful Model validation + * and right before the model UPDATE DB statement execution. + * + * Usually it is triggered as part of the App.Save() in the following firing order: + * OnModelUpdate { + * ``` + * -> OnModelValidate (skipped with App.SaveNoValidate()) + * -> OnModelUpdateExecute + * ``` + * } + * + * Note that successful execution doesn't guarantee that the model + * is persisted in the database since its wrapping transaction may have been + * committed yet. + * If you want to listen to only the actual persisted events, + * you can bind to [OnModelAfterUpdateSuccess] or [OnModelAfterUpdateError] hooks. + * + * For convenience, if you want to listen to only the Record models + * events without doing manual type assertion, you can attach to the OnRecord* proxy hooks. + * + * If the optional "tags" list (Collection id/name, Model table name, etc.) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - validate(): void - } - interface TestEmailSend { + onModelUpdateExecute(...tags: string[]): (hook.TaggedHook) /** - * Submit validates and sends a test email to the form.Email address. + * OnModelAfterUpdateSuccess is triggered after each successful + * Model DB update persistence. + * + * Note that when a Model is persisted as part of a transaction, + * this hook is delayed and executed only AFTER the transaction has been committed. + * This hook is NOT triggered in case the transaction rollbacks + * (aka. when the model changes weren't persisted). + * + * For convenience, if you want to listen to only the Record models + * events without doing manual type assertion, you can attach to the OnRecord* proxy hooks. + * + * If the optional "tags" list (Collection id/name, Model table name, etc.) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - submit(): void - } - /** - * TestS3Filesystem defines a S3 filesystem connection test. - */ - interface TestS3Filesystem { + onModelAfterUpdateSuccess(...tags: string[]): (hook.TaggedHook) /** - * The name of the filesystem - storage or backups + * OnModelAfterUpdateError is triggered after each failed + * Model DB update persistence. + * + * Note that the execution of this hook is either immediate or delayed + * depending on the error: + * ``` + * - "immediate" on App.Save() failure + * - "delayed" on transaction rollback + * ``` + * + * For convenience, if you want to listen to only the Record models + * events without doing manual type assertion, you can attach to the OnRecord* proxy hooks. + * + * If the optional "tags" list (Collection id/name, Model table name, etc.) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - filesystem: string - } - interface newTestS3Filesystem { + onModelAfterUpdateError(...tags: string[]): (hook.TaggedHook) /** - * NewTestS3Filesystem creates and initializes new TestS3Filesystem form. + * OnModelDelete is triggered every time when a new model is being deleted + * (e.g. triggered by App.Delete()). + * + * Note that successful execution doesn't guarantee that the model + * is deleted from the database since its wrapping transaction may + * not have been committed yet. + * If you want to listen to only the actual persisted deleted events, you can + * bind to [OnModelAfterDeleteSuccess] or [OnModelAfterDeleteError] hooks. + * + * For convenience, if you want to listen to only the Record models + * events without doing manual type assertion, you can attach to the OnRecord* proxy hooks. + * + * If the optional "tags" list (Collection id/name, Model table name, etc.) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (app: CoreApp): (TestS3Filesystem) - } - interface TestS3Filesystem { + onModelDelete(...tags: string[]): (hook.TaggedHook) /** - * Validate makes the form validatable by implementing [validation.Validatable] interface. + * OnModelUpdateExecute is triggered right before the model + * DELETE DB statement execution. + * + * Usually it is triggered as part of the App.Delete() in the following firing order: + * OnModelDelete { + * ``` + * -> (internal delete checks) + * -> OnModelDeleteExecute + * ``` + * } + * + * Note that successful execution doesn't guarantee that the model + * is deleted from the database since its wrapping transaction may + * not have been committed yet. + * If you want to listen to only the actual persisted deleted events, you can + * bind to [OnModelAfterDeleteSuccess] or [OnModelAfterDeleteError] hooks. + * + * For convenience, if you want to listen to only the Record models + * events without doing manual type assertion, you can attach to the OnRecord* proxy hooks. + * + * If the optional "tags" list (Collection id/name, Model table name, etc.) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - validate(): void - } - interface TestS3Filesystem { + onModelDeleteExecute(...tags: string[]): (hook.TaggedHook) /** - * Submit validates and performs a S3 filesystem connection test. + * OnModelAfterDeleteSuccess is triggered after each successful + * Model DB delete persistence. + * + * Note that when a Model is deleted as part of a transaction, + * this hook is delayed and executed only AFTER the transaction has been committed. + * This hook is NOT triggered in case the transaction rollbacks + * (aka. when the model delete wasn't persisted). + * + * For convenience, if you want to listen to only the Record models + * events without doing manual type assertion, you can attach to the OnRecord* proxy hooks. + * + * If the optional "tags" list (Collection id/name, Model table name, etc.) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - submit(): void - } -} - -/** - * Package apis implements the default PocketBase api services and middlewares. - */ -namespace apis { - interface adminApi { - } - // @ts-ignore - import validation = ozzo_validation - /** - * ApiError defines the struct for a basic api error response. - */ - interface ApiError { - code: number - message: string - data: _TygojaDict - } - interface ApiError { + onModelAfterDeleteSuccess(...tags: string[]): (hook.TaggedHook) /** - * Error makes it compatible with the `error` interface. + * OnModelAfterDeleteError is triggered after each failed + * Model DB delete persistence. + * + * Note that the execution of this hook is either immediate or delayed + * depending on the error: + * ``` + * - "immediate" on App.Delete() failure + * - "delayed" on transaction rollback + * ``` + * + * For convenience, if you want to listen to only the Record models + * events without doing manual type assertion, you can attach to the OnRecord* proxy hooks. + * + * If the optional "tags" list (Collection id/name, Model table name, etc.) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - error(): string - } - interface ApiError { + onModelAfterDeleteError(...tags: string[]): (hook.TaggedHook) /** - * RawData returns the unformatted error data (could be an internal error, text, etc.) + * OnRecordEnrich is triggered every time when a record is enriched + * (as part of the builtin Record responses, during realtime message seriazation, or when [apis.EnrichRecord] is invoked). + * + * It could be used for example to redact/hide or add computed temporary + * Record model props only for the specific request info. For example: + * + * app.OnRecordEnrich("posts").BindFunc(func(e core.*RecordEnrichEvent) { + * ``` + * // hide one or more fields + * e.Record.Hide("role") + * + * // add new custom field for registered users + * if e.RequestInfo.Auth != nil && e.RequestInfo.Auth.Collection().Name == "users" { + * e.Record.WithCustomData(true) // for security requires explicitly allowing it + * e.Record.Set("computedScore", e.Record.GetInt("score") * e.RequestInfo.Auth.GetInt("baseScore")) + * } + * + * return e.Next() + * ``` + * }) + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - rawData(): any - } - interface newNotFoundError { + onRecordEnrich(...tags: string[]): (hook.TaggedHook) /** - * NewNotFoundError creates and returns 404 `ApiError`. + * OnRecordValidate is a Record proxy model hook of [OnModelValidate]. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (message: string, data: any): (ApiError) - } - interface newBadRequestError { + onRecordValidate(...tags: string[]): (hook.TaggedHook) /** - * NewBadRequestError creates and returns 400 `ApiError`. + * OnRecordCreate is a Record proxy model hook of [OnModelCreate]. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (message: string, data: any): (ApiError) - } - interface newForbiddenError { + onRecordCreate(...tags: string[]): (hook.TaggedHook) /** - * NewForbiddenError creates and returns 403 `ApiError`. + * OnRecordCreateExecute is a Record proxy model hook of [OnModelCreateExecute]. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (message: string, data: any): (ApiError) - } - interface newUnauthorizedError { + onRecordCreateExecute(...tags: string[]): (hook.TaggedHook) /** - * NewUnauthorizedError creates and returns 401 `ApiError`. + * OnRecordAfterCreateSuccess is a Record proxy model hook of [OnModelAfterCreateSuccess]. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (message: string, data: any): (ApiError) - } - interface newApiError { + onRecordAfterCreateSuccess(...tags: string[]): (hook.TaggedHook) /** - * NewApiError creates and returns new normalized `ApiError` instance. + * OnRecordAfterCreateError is a Record proxy model hook of [OnModelAfterCreateError]. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (status: number, message: string, data: any): (ApiError) - } - interface backupApi { - } - interface initApi { + onRecordAfterCreateError(...tags: string[]): (hook.TaggedHook) /** - * InitApi creates a configured echo instance with registered - * system and app specific routes and middlewares. + * OnRecordUpdate is a Record proxy model hook of [OnModelUpdate]. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (app: CoreApp): (echo.Echo) - } - interface staticDirectoryHandler { + onRecordUpdate(...tags: string[]): (hook.TaggedHook) /** - * StaticDirectoryHandler is similar to `echo.StaticDirectoryHandler` - * but without the directory redirect which conflicts with RemoveTrailingSlash middleware. - * - * If a file resource is missing and indexFallback is set, the request - * will be forwarded to the base index.html (useful also for SPA). + * OnRecordUpdateExecute is a Record proxy model hook of [OnModelUpdateExecute]. * - * @see https://github.com/labstack/echo/issues/2211 + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (fileSystem: fs.FS, indexFallback: boolean): echo.HandlerFunc - } - interface collectionApi { - } - interface fileApi { - } - interface healthApi { - } - interface healthCheckResponse { - message: string - code: number - data: { - canBackup: boolean - } - } - interface logsApi { - } - interface requireGuestOnly { + onRecordUpdateExecute(...tags: string[]): (hook.TaggedHook) /** - * RequireGuestOnly middleware requires a request to NOT have a valid - * Authorization header. + * OnRecordAfterUpdateSuccess is a Record proxy model hook of [OnModelAfterUpdateSuccess]. * - * This middleware is the opposite of [apis.RequireAdminOrRecordAuth()]. + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (): echo.MiddlewareFunc - } - interface requireRecordAuth { + onRecordAfterUpdateSuccess(...tags: string[]): (hook.TaggedHook) /** - * RequireRecordAuth middleware requires a request to have - * a valid record auth Authorization header. - * - * The auth record could be from any collection. + * OnRecordAfterUpdateError is a Record proxy model hook of [OnModelAfterUpdateError]. * - * You can further filter the allowed record auth collections by - * specifying their names. + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. + */ + onRecordAfterUpdateError(...tags: string[]): (hook.TaggedHook) + /** + * OnRecordDelete is a Record proxy model hook of [OnModelDelete]. * - * Example: + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. + */ + onRecordDelete(...tags: string[]): (hook.TaggedHook) + /** + * OnRecordDeleteExecute is a Record proxy model hook of [OnModelDeleteExecute]. * - * ``` - * apis.RequireRecordAuth() - * ``` + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. + */ + onRecordDeleteExecute(...tags: string[]): (hook.TaggedHook) + /** + * OnRecordAfterDeleteSuccess is a Record proxy model hook of [OnModelAfterDeleteSuccess]. * - * Or: + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. + */ + onRecordAfterDeleteSuccess(...tags: string[]): (hook.TaggedHook) + /** + * OnRecordAfterDeleteError is a Record proxy model hook of [OnModelAfterDeleteError]. * - * ``` - * apis.RequireRecordAuth("users", "supervisors") - * ``` + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. + */ + onRecordAfterDeleteError(...tags: string[]): (hook.TaggedHook) + /** + * OnCollectionValidate is a Collection proxy model hook of [OnModelValidate]. * - * To restrict the auth record only to the loaded context collection, - * use [apis.RequireSameContextRecordAuth()] instead. + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (...optCollectionNames: string[]): echo.MiddlewareFunc - } - interface requireSameContextRecordAuth { + onCollectionValidate(...tags: string[]): (hook.TaggedHook) /** - * RequireSameContextRecordAuth middleware requires a request to have - * a valid record Authorization header. + * OnCollectionCreate is a Collection proxy model hook of [OnModelCreate]. * - * The auth record must be from the same collection already loaded in the context. + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (): echo.MiddlewareFunc - } - interface requireAdminAuth { + onCollectionCreate(...tags: string[]): (hook.TaggedHook) /** - * RequireAdminAuth middleware requires a request to have - * a valid admin Authorization header. + * OnCollectionCreateExecute is a Collection proxy model hook of [OnModelCreateExecute]. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (): echo.MiddlewareFunc - } - interface requireAdminAuthOnlyIfAny { + onCollectionCreateExecute(...tags: string[]): (hook.TaggedHook) /** - * RequireAdminAuthOnlyIfAny middleware requires a request to have - * a valid admin Authorization header ONLY if the application has - * at least 1 existing Admin model. + * OnCollectionAfterCreateSuccess is a Collection proxy model hook of [OnModelAfterCreateSuccess]. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (app: CoreApp): echo.MiddlewareFunc - } - interface requireAdminOrRecordAuth { + onCollectionAfterCreateSuccess(...tags: string[]): (hook.TaggedHook) /** - * RequireAdminOrRecordAuth middleware requires a request to have - * a valid admin or record Authorization header set. + * OnCollectionAfterCreateError is a Collection proxy model hook of [OnModelAfterCreateError]. * - * You can further filter the allowed auth record collections by providing their names. + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. + */ + onCollectionAfterCreateError(...tags: string[]): (hook.TaggedHook) + /** + * OnCollectionUpdate is a Collection proxy model hook of [OnModelUpdate]. * - * This middleware is the opposite of [apis.RequireGuestOnly()]. + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (...optCollectionNames: string[]): echo.MiddlewareFunc - } - interface requireAdminOrOwnerAuth { + onCollectionUpdate(...tags: string[]): (hook.TaggedHook) /** - * RequireAdminOrOwnerAuth middleware requires a request to have - * a valid admin or auth record owner Authorization header set. + * OnCollectionUpdateExecute is a Collection proxy model hook of [OnModelUpdateExecute]. * - * This middleware is similar to [apis.RequireAdminOrRecordAuth()] but - * for the auth record token expects to have the same id as the path - * parameter ownerIdParam (default to "id" if empty). + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (ownerIdParam: string): echo.MiddlewareFunc - } - interface loadAuthContext { + onCollectionUpdateExecute(...tags: string[]): (hook.TaggedHook) /** - * LoadAuthContext middleware reads the Authorization request header - * and loads the token related record or admin instance into the - * request's context. + * OnCollectionAfterUpdateSuccess is a Collection proxy model hook of [OnModelAfterUpdateSuccess]. * - * This middleware is expected to be already registered by default for all routes. + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (app: CoreApp): echo.MiddlewareFunc - } - interface loadCollectionContext { + onCollectionAfterUpdateSuccess(...tags: string[]): (hook.TaggedHook) /** - * LoadCollectionContext middleware finds the collection with related - * path identifier and loads it into the request context. + * OnCollectionAfterUpdateError is a Collection proxy model hook of [OnModelAfterUpdateError]. * - * Set optCollectionTypes to further filter the found collection by its type. + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (app: CoreApp, ...optCollectionTypes: string[]): echo.MiddlewareFunc - } - interface activityLogger { + onCollectionAfterUpdateError(...tags: string[]): (hook.TaggedHook) /** - * ActivityLogger middleware takes care to save the request information - * into the logs database. + * OnCollectionDelete is a Collection proxy model hook of [OnModelDelete]. * - * The middleware does nothing if the app logs retention period is zero - * (aka. app.Settings().Logs.MaxDays = 0). + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (app: CoreApp): echo.MiddlewareFunc - } - interface realtimeApi { - } - /** - * recordData represents the broadcasted record subscrition message data. - */ - interface recordData { - record: any // map or models.Record - action: string - } - interface getter { - [key:string]: any; - get(_arg0: string): any - } - interface recordAuthApi { - } - interface providerInfo { - name: string - displayName: string - state: string - authUrl: string + onCollectionDelete(...tags: string[]): (hook.TaggedHook) /** - * technically could be omitted if the provider doesn't support PKCE, - * but to avoid breaking existing typed clients we'll return them as empty string + * OnCollectionDeleteExecute is a Collection proxy model hook of [OnModelDeleteExecute]. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - codeVerifier: string - codeChallenge: string - codeChallengeMethod: string - } - interface oauth2RedirectData { - state: string - code: string - error: string - } - interface recordApi { - } - interface requestData { + onCollectionDeleteExecute(...tags: string[]): (hook.TaggedHook) /** - * Deprecated: Use RequestInfo instead. + * OnCollectionAfterDeleteSuccess is a Collection proxy model hook of [OnModelAfterDeleteSuccess]. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (c: echo.Context): (models.RequestInfo) - } - interface requestInfo { + onCollectionAfterDeleteSuccess(...tags: string[]): (hook.TaggedHook) /** - * RequestInfo exports cached common request data fields - * (query, body, logged auth state, etc.) from the provided context. + * OnCollectionAfterDeleteError is a Collection proxy model hook of [OnModelAfterDeleteError]. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (c: echo.Context): (models.RequestInfo) - } - interface recordAuthResponse { + onCollectionAfterDeleteError(...tags: string[]): (hook.TaggedHook) /** - * RecordAuthResponse writes standardised json record auth response - * into the specified request context. + * OnMailerSend hook is triggered every time when a new email is + * being sent using the [App.NewMailClient()] instance. + * + * It allows intercepting the email message or to use a custom mailer client. */ - (app: CoreApp, c: echo.Context, authRecord: models.Record, meta: any, ...finalizers: ((token: string) => void)[]): void - } - interface enrichRecord { + onMailerSend(): (hook.Hook) /** - * EnrichRecord parses the request context and enrich the provided record: - * ``` - * - expands relations (if defaultExpands and/or ?expand query param is set) - * - ensures that the emails of the auth record and its expanded auth relations - * are visible only for the current logged admin, record owner or record with manage access - * ``` + * OnMailerRecordAuthAlertSend hook is triggered when + * sending a new device login auth alert email, allowing you to + * intercept and customize the email message that is being sent. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (c: echo.Context, dao: daos.Dao, record: models.Record, ...defaultExpands: string[]): void - } - interface enrichRecords { + onMailerRecordAuthAlertSend(...tags: string[]): (hook.TaggedHook) /** - * EnrichRecords parses the request context and enriches the provided records: - * ``` - * - expands relations (if defaultExpands and/or ?expand query param is set) - * - ensures that the emails of the auth records and their expanded auth relations - * are visible only for the current logged admin, record owner or record with manage access - * ``` + * OnMailerBeforeRecordResetPasswordSend hook is triggered when + * sending a password reset email to an auth record, allowing + * you to intercept and customize the email message that is being sent. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (c: echo.Context, dao: daos.Dao, records: Array<(models.Record | undefined)>, ...defaultExpands: string[]): void - } - /** - * ServeConfig defines a configuration struct for apis.Serve(). - */ - interface ServeConfig { + onMailerRecordPasswordResetSend(...tags: string[]): (hook.TaggedHook) /** - * ShowStartBanner indicates whether to show or hide the server start console message. + * OnMailerBeforeRecordVerificationSend hook is triggered when + * sending a verification email to an auth record, allowing + * you to intercept and customize the email message that is being sent. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - showStartBanner: boolean + onMailerRecordVerificationSend(...tags: string[]): (hook.TaggedHook) /** - * HttpAddr is the TCP address to listen for the HTTP server (eg. `127.0.0.1:80`). + * OnMailerRecordEmailChangeSend hook is triggered when sending a + * confirmation new address email to an auth record, allowing + * you to intercept and customize the email message that is being sent. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - httpAddr: string + onMailerRecordEmailChangeSend(...tags: string[]): (hook.TaggedHook) /** - * HttpsAddr is the TCP address to listen for the HTTPS server (eg. `127.0.0.1:443`). + * OnMailerRecordOTPSend hook is triggered when sending an OTP email + * to an auth record, allowing you to intercept and customize the + * email message that is being sent. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - httpsAddr: string + onMailerRecordOTPSend(...tags: string[]): (hook.TaggedHook) /** - * Optional domains list to use when issuing the TLS certificate. + * OnRealtimeConnectRequest hook is triggered when establishing the SSE client connection. * - * If not set, the host from the bound server address will be used. + * Any execution after e.Next() of a hook handler happens after the client disconnects. + */ + onRealtimeConnectRequest(): (hook.Hook) + /** + * OnRealtimeMessageSend hook is triggered when sending an SSE message to a client. + */ + onRealtimeMessageSend(): (hook.Hook) + /** + * OnRealtimeSubscribeRequest hook is triggered when updating the + * client subscriptions, allowing you to further validate and + * modify the submitted change. + */ + onRealtimeSubscribeRequest(): (hook.Hook) + /** + * OnSettingsListRequest hook is triggered on each API Settings list request. * - * For convenience, for each "non-www" domain a "www" entry and - * redirect will be automatically added. + * Could be used to validate or modify the response before returning it to the client. */ - certificateDomains: Array + onSettingsListRequest(): (hook.Hook) /** - * AllowedOrigins is an optional list of CORS origins (default to "*"). + * OnSettingsUpdateRequest hook is triggered on each API Settings update request. + * + * Could be used to additionally validate the request data or + * implement completely different persistence behavior. */ - allowedOrigins: Array - } - interface serve { + onSettingsUpdateRequest(): (hook.Hook) /** - * Serve starts a new app web server. + * OnSettingsReload hook is triggered every time when the App.Settings() + * is being replaced with a new state. * - * NB! The app should be bootstrapped before starting the web server. + * Calling App.Settings() after e.Next() returns the new state. + */ + onSettingsReload(): (hook.Hook) + /** + * OnFileDownloadRequest hook is triggered before each API File download request. * - * Example: + * Could be used to validate or modify the file response before + * returning it to the client. + */ + onFileDownloadRequest(...tags: string[]): (hook.TaggedHook) + /** + * OnFileBeforeTokenRequest hook is triggered on each auth file token API request. * - * ``` - * app.Bootstrap() - * apis.Serve(app, apis.ServeConfig{ - * HttpAddr: "127.0.0.1:8080", - * ShowStartBanner: false, - * }) - * ``` + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (app: CoreApp, config: ServeConfig): (http.Server) - } - interface migrationsConnection { - db?: dbx.DB - migrationsList: migrate.MigrationsList - } - interface settingsApi { - } -} - -namespace pocketbase { - /** - * appWrapper serves as a private CoreApp instance wrapper. - */ - type _subKNSIF = CoreApp - interface appWrapper extends _subKNSIF { - } - /** - * PocketBase defines a PocketBase app launcher. - * - * It implements [CoreApp] via embedding and all of the app interface methods - * could be accessed directly through the instance (eg. PocketBase.DataDir()). - */ - type _subMNsmB = appWrapper - interface PocketBase extends _subMNsmB { + onFileTokenRequest(...tags: string[]): (hook.TaggedHook) /** - * RootCmd is the main console command + * OnRecordAuthRequest hook is triggered on each successful API + * record authentication request (sign-in, token refresh, etc.). + * + * Could be used to additionally validate or modify the authenticated + * record data and token. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - rootCmd?: cobra.Command - } - /** - * Config is the PocketBase initialization config struct. - */ - interface Config { + onRecordAuthRequest(...tags: string[]): (hook.TaggedHook) /** - * optional default values for the console flags + * OnRecordAuthWithPasswordRequest hook is triggered on each + * Record auth with password API request. + * + * [RecordAuthWithPasswordRequestEvent.Record] could be nil if no matching identity is found, allowing + * you to manually locate a different Record model (by reassigning [RecordAuthWithPasswordRequestEvent.Record]). + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - defaultDev: boolean - defaultDataDir: string // if not set, it will fallback to "./pb_data" - defaultEncryptionEnv: string + onRecordAuthWithPasswordRequest(...tags: string[]): (hook.TaggedHook) /** - * hide the default console server info on app startup + * OnRecordAuthWithOAuth2Request hook is triggered on each Record + * OAuth2 sign-in/sign-up API request (after token exchange and before external provider linking). + * + * If [RecordAuthWithOAuth2RequestEvent.Record] is not set, then the OAuth2 + * request will try to create a new auth Record. + * + * To assign or link a different existing record model you can + * change the [RecordAuthWithOAuth2RequestEvent.Record] field. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - hideStartBanner: boolean + onRecordAuthWithOAuth2Request(...tags: string[]): (hook.TaggedHook) /** - * optional DB configurations + * OnRecordAuthRefreshRequest hook is triggered on each Record + * auth refresh API request (right before generating a new auth token). + * + * Could be used to additionally validate the request data or implement + * completely different auth refresh behavior. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - dataMaxOpenConns: number // default to core.DefaultDataMaxOpenConns - dataMaxIdleConns: number // default to core.DefaultDataMaxIdleConns - logsMaxOpenConns: number // default to core.DefaultLogsMaxOpenConns - logsMaxIdleConns: number // default to core.DefaultLogsMaxIdleConns - } - interface _new { + onRecordAuthRefreshRequest(...tags: string[]): (hook.TaggedHook) /** - * New creates a new PocketBase instance with the default configuration. - * Use [NewWithConfig()] if you want to provide a custom configuration. + * OnRecordRequestPasswordResetRequest hook is triggered on + * each Record request password reset API request. * - * Note that the application will not be initialized/bootstrapped yet, - * aka. DB connections, migrations, app settings, etc. will not be accessible. - * Everything will be initialized when [Start()] is executed. - * If you want to initialize the application before calling [Start()], - * then you'll have to manually call [Bootstrap()]. + * Could be used to additionally validate the request data or implement + * completely different password reset behavior. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (): (PocketBase) - } - interface newWithConfig { + onRecordRequestPasswordResetRequest(...tags: string[]): (hook.TaggedHook) /** - * NewWithConfig creates a new PocketBase instance with the provided config. + * OnRecordConfirmPasswordResetRequest hook is triggered on + * each Record confirm password reset API request. * - * Note that the application will not be initialized/bootstrapped yet, - * aka. DB connections, migrations, app settings, etc. will not be accessible. - * Everything will be initialized when [Start()] is executed. - * If you want to initialize the application before calling [Start()], - * then you'll have to manually call [Bootstrap()]. + * Could be used to additionally validate the request data or implement + * completely different persistence behavior. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - (config: Config): (PocketBase) - } - interface PocketBase { + onRecordConfirmPasswordResetRequest(...tags: string[]): (hook.TaggedHook) /** - * Start starts the application, aka. registers the default system - * commands (serve, migrate, version) and executes pb.RootCmd. + * OnRecordRequestVerificationRequest hook is triggered on + * each Record request verification API request. + * + * Could be used to additionally validate the loaded request data or implement + * completely different verification behavior. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - start(): void - } - interface PocketBase { + onRecordRequestVerificationRequest(...tags: string[]): (hook.TaggedHook) /** - * Execute initializes the application (if not already) and executes - * the pb.RootCmd with graceful shutdown support. + * OnRecordConfirmVerificationRequest hook is triggered on each + * Record confirm verification API request. * - * This method differs from pb.Start() by not registering the default - * system commands! + * Could be used to additionally validate the request data or implement + * completely different persistence behavior. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - execute(): void - } - /** - * coloredWriter is a small wrapper struct to construct a [color.Color] writter. - */ - interface coloredWriter { - } - interface coloredWriter { + onRecordConfirmVerificationRequest(...tags: string[]): (hook.TaggedHook) /** - * Write writes the p bytes using the colored writer. + * OnRecordRequestEmailChangeRequest hook is triggered on each + * Record request email change API request. + * + * Could be used to additionally validate the request data or implement + * completely different request email change behavior. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - write(p: string|Array): number - } -} - -/** - * Package syscall contains an interface to the low-level operating system - * primitives. The details vary depending on the underlying system, and - * by default, godoc will display the syscall documentation for the current - * system. If you want godoc to display syscall documentation for another - * system, set $GOOS and $GOARCH to the desired system. For example, if - * you want to view documentation for freebsd/arm on linux/amd64, set $GOOS - * to freebsd and $GOARCH to arm. - * The primary use of syscall is inside other packages that provide a more - * portable interface to the system, such as "os", "time" and "net". Use - * those packages rather than this one if you can. - * For details of the functions and data types in this package consult - * the manuals for the appropriate operating system. - * These calls return err == nil to indicate success; otherwise - * err is an operating system error describing the failure. - * On most systems, that error has type [Errno]. - * - * NOTE: Most of the functions, types, and constants defined in - * this package are also available in the [golang.org/x/sys] package. - * That package has more system call support than this one, - * and most new code should prefer that package where possible. - * See https://golang.org/s/go1.4-syscall for more information. - */ -namespace syscall { - interface SysProcAttr { - chroot: string // Chroot. - credential?: Credential // Credential. + onRecordRequestEmailChangeRequest(...tags: string[]): (hook.TaggedHook) /** - * Ptrace tells the child to call ptrace(PTRACE_TRACEME). - * Call runtime.LockOSThread before starting a process with this set, - * and don't call UnlockOSThread until done with PtraceSyscall calls. + * OnRecordConfirmEmailChangeRequest hook is triggered on each + * Record confirm email change API request. + * + * Could be used to additionally validate the request data or implement + * completely different persistence behavior. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - ptrace: boolean - setsid: boolean // Create session. + onRecordConfirmEmailChangeRequest(...tags: string[]): (hook.TaggedHook) /** - * Setpgid sets the process group ID of the child to Pgid, - * or, if Pgid == 0, to the new child's process ID. + * OnRecordRequestOTPRequest hook is triggered on each Record + * request OTP API request. + * + * [RecordCreateOTPRequestEvent.Record] could be nil if no matching identity is found, allowing + * you to manually create or locate a different Record model (by reassigning [RecordCreateOTPRequestEvent.Record]). + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - setpgid: boolean + onRecordRequestOTPRequest(...tags: string[]): (hook.TaggedHook) /** - * Setctty sets the controlling terminal of the child to - * file descriptor Ctty. Ctty must be a descriptor number - * in the child process: an index into ProcAttr.Files. - * This is only meaningful if Setsid is true. + * OnRecordAuthWithOTPRequest hook is triggered on each Record + * auth with OTP API request. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - setctty: boolean - noctty: boolean // Detach fd 0 from controlling terminal. - ctty: number // Controlling TTY fd. + onRecordAuthWithOTPRequest(...tags: string[]): (hook.TaggedHook) /** - * Foreground places the child process group in the foreground. - * This implies Setpgid. The Ctty field must be set to - * the descriptor of the controlling TTY. - * Unlike Setctty, in this case Ctty must be a descriptor - * number in the parent process. + * OnRecordsListRequest hook is triggered on each API Records list request. + * + * Could be used to validate or modify the response before returning it to the client. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - foreground: boolean - pgid: number // Child's process group ID if Setpgid. + onRecordsListRequest(...tags: string[]): (hook.TaggedHook) /** - * Pdeathsig, if non-zero, is a signal that the kernel will send to - * the child process when the creating thread dies. Note that the signal - * is sent on thread termination, which may happen before process termination. - * There are more details at https://go.dev/issue/27505. + * OnRecordViewRequest hook is triggered on each API Record view request. + * + * Could be used to validate or modify the response before returning it to the client. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - pdeathsig: Signal - cloneflags: number // Flags for clone calls. - unshareflags: number // Flags for unshare calls. - uidMappings: Array // User ID mappings for user namespaces. - gidMappings: Array // Group ID mappings for user namespaces. + onRecordViewRequest(...tags: string[]): (hook.TaggedHook) /** - * GidMappingsEnableSetgroups enabling setgroups syscall. - * If false, then setgroups syscall will be disabled for the child process. - * This parameter is no-op if GidMappings == nil. Otherwise for unprivileged - * users this should be set to false for mappings work. + * OnRecordCreateRequest hook is triggered on each API Record create request. + * + * Could be used to additionally validate the request data or implement + * completely different persistence behavior. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - gidMappingsEnableSetgroups: boolean - ambientCaps: Array // Ambient capabilities. - useCgroupFD: boolean // Whether to make use of the CgroupFD field. - cgroupFD: number // File descriptor of a cgroup to put the new process into. + onRecordCreateRequest(...tags: string[]): (hook.TaggedHook) /** - * PidFD, if not nil, is used to store the pidfd of a child, if the - * functionality is supported by the kernel, or -1. Note *PidFD is - * changed only if the process starts successfully. + * OnRecordUpdateRequest hook is triggered on each API Record update request. + * + * Could be used to additionally validate the request data or implement + * completely different persistence behavior. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. */ - pidFD?: number + onRecordUpdateRequest(...tags: string[]): (hook.TaggedHook) + /** + * OnRecordDeleteRequest hook is triggered on each API Record delete request. + * + * Could be used to additionally validate the request data or implement + * completely different delete behavior. + * + * If the optional "tags" list (Collection ids or names) is specified, + * then all event handlers registered via the created hook will be + * triggered and called only if their event data origin matches the tags. + */ + onRecordDeleteRequest(...tags: string[]): (hook.TaggedHook) + /** + * OnCollectionsListRequest hook is triggered on each API Collections list request. + * + * Could be used to validate or modify the response before returning it to the client. + */ + onCollectionsListRequest(): (hook.Hook) + /** + * OnCollectionViewRequest hook is triggered on each API Collection view request. + * + * Could be used to validate or modify the response before returning it to the client. + */ + onCollectionViewRequest(): (hook.Hook) + /** + * OnCollectionCreateRequest hook is triggered on each API Collection create request. + * + * Could be used to additionally validate the request data or implement + * completely different persistence behavior. + */ + onCollectionCreateRequest(): (hook.Hook) + /** + * OnCollectionUpdateRequest hook is triggered on each API Collection update request. + * + * Could be used to additionally validate the request data or implement + * completely different persistence behavior. + */ + onCollectionUpdateRequest(): (hook.Hook) + /** + * OnCollectionDeleteRequest hook is triggered on each API Collection delete request. + * + * Could be used to additionally validate the request data or implement + * completely different delete behavior. + */ + onCollectionDeleteRequest(): (hook.Hook) + /** + * OnCollectionsBeforeImportRequest hook is triggered on each API + * collections import request. + * + * Could be used to additionally validate the imported collections or + * to implement completely different import behavior. + */ + onCollectionsImportRequest(): (hook.Hook) + /** + * OnBatchRequest hook is triggered on each API batch request. + * + * Could be used to additionally validate or modify the submitted batch requests. + */ + onBatchRequest(): (hook.Hook) } // @ts-ignore - import errorspkg = errors + import validation = ozzo_validation /** - * A RawConn is a raw network connection. + * AuthOrigin defines a Record proxy for working with the authOrigins collection. */ - interface RawConn { - [key:string]: any; + type _suxhyqw = Record + interface AuthOrigin extends _suxhyqw { + } + interface newAuthOrigin { /** - * Control invokes f on the underlying connection's file - * descriptor or handle. - * The file descriptor fd is guaranteed to remain valid while - * f executes but not after f returns. + * NewAuthOrigin instantiates and returns a new blank *AuthOrigin model. + * + * Example usage: + * + * ``` + * origin := core.NewOrigin(app) + * origin.SetRecordRef(user.Id) + * origin.SetCollectionRef(user.Collection().Id) + * origin.SetFingerprint("...") + * app.Save(origin) + * ``` */ - control(f: (fd: number) => void): void + (app: App): (AuthOrigin) + } + interface AuthOrigin { /** - * Read invokes f on the underlying connection's file - * descriptor or handle; f is expected to try to read from the - * file descriptor. - * If f returns true, Read returns. Otherwise Read blocks - * waiting for the connection to be ready for reading and - * tries again repeatedly. - * The file descriptor is guaranteed to remain valid while f - * executes but not after f returns. + * PreValidate implements the [PreValidator] interface and checks + * whether the proxy is properly loaded. */ - read(f: (fd: number) => boolean): void + preValidate(ctx: context.Context, app: App): void + } + interface AuthOrigin { /** - * Write is like Read but for writing. + * ProxyRecord returns the proxied Record model. */ - write(f: (fd: number) => boolean): void + proxyRecord(): (Record) } - // @ts-ignore - import runtimesyscall = syscall - /** - * An Errno is an unsigned number describing an error condition. - * It implements the error interface. The zero Errno is by convention - * a non-error, so code to convert from Errno to error should use: - * - * ``` - * err = nil - * if errno != 0 { - * err = errno - * } - * ``` - * - * Errno values can be tested against error values using [errors.Is]. - * For example: - * - * ``` - * _, _, err := syscall.Syscall(...) - * if errors.Is(err, fs.ErrNotExist) ... - * ``` - */ - interface Errno extends Number{} - interface Errno { - error(): string + interface AuthOrigin { + /** + * SetProxyRecord loads the specified record model into the current proxy. + */ + setProxyRecord(record: Record): void } - interface Errno { - is(target: Error): boolean + interface AuthOrigin { + /** + * CollectionRef returns the "collectionRef" field value. + */ + collectionRef(): string } - interface Errno { - temporary(): boolean + interface AuthOrigin { + /** + * SetCollectionRef updates the "collectionRef" record field value. + */ + setCollectionRef(collectionId: string): void } - interface Errno { - timeout(): boolean + interface AuthOrigin { + /** + * RecordRef returns the "recordRef" record field value. + */ + recordRef(): string } -} - -/** - * Package time provides functionality for measuring and displaying time. - * - * The calendrical calculations always assume a Gregorian calendar, with - * no leap seconds. - * - * # Monotonic Clocks - * - * Operating systems provide both a “wall clock,” which is subject to - * changes for clock synchronization, and a “monotonic clock,” which is - * not. The general rule is that the wall clock is for telling time and - * the monotonic clock is for measuring time. Rather than split the API, - * in this package the Time returned by [time.Now] contains both a wall - * clock reading and a monotonic clock reading; later time-telling - * operations use the wall clock reading, but later time-measuring - * operations, specifically comparisons and subtractions, use the - * monotonic clock reading. - * - * For example, this code always computes a positive elapsed time of - * approximately 20 milliseconds, even if the wall clock is changed during - * the operation being timed: - * - * ``` - * start := time.Now() - * ... operation that takes 20 milliseconds ... - * t := time.Now() - * elapsed := t.Sub(start) - * ``` - * - * Other idioms, such as [time.Since](start), [time.Until](deadline), and - * time.Now().Before(deadline), are similarly robust against wall clock - * resets. - * - * The rest of this section gives the precise details of how operations - * use monotonic clocks, but understanding those details is not required - * to use this package. - * - * The Time returned by time.Now contains a monotonic clock reading. - * If Time t has a monotonic clock reading, t.Add adds the same duration to - * both the wall clock and monotonic clock readings to compute the result. - * Because t.AddDate(y, m, d), t.Round(d), and t.Truncate(d) are wall time - * computations, they always strip any monotonic clock reading from their results. - * Because t.In, t.Local, and t.UTC are used for their effect on the interpretation - * of the wall time, they also strip any monotonic clock reading from their results. - * The canonical way to strip a monotonic clock reading is to use t = t.Round(0). - * - * If Times t and u both contain monotonic clock readings, the operations - * t.After(u), t.Before(u), t.Equal(u), t.Compare(u), and t.Sub(u) are carried out - * using the monotonic clock readings alone, ignoring the wall clock - * readings. If either t or u contains no monotonic clock reading, these - * operations fall back to using the wall clock readings. - * - * On some systems the monotonic clock will stop if the computer goes to sleep. - * On such a system, t.Sub(u) may not accurately reflect the actual - * time that passed between t and u. The same applies to other functions and - * methods that subtract times, such as [Since], [Until], [Before], [After], - * [Add], [Sub], [Equal] and [Compare]. In some cases, you may need to strip - * the monotonic clock to get accurate results. - * - * Because the monotonic clock reading has no meaning outside - * the current process, the serialized forms generated by t.GobEncode, - * t.MarshalBinary, t.MarshalJSON, and t.MarshalText omit the monotonic - * clock reading, and t.Format provides no format for it. Similarly, the - * constructors [time.Date], [time.Parse], [time.ParseInLocation], and [time.Unix], - * as well as the unmarshalers t.GobDecode, t.UnmarshalBinary. - * t.UnmarshalJSON, and t.UnmarshalText always create times with - * no monotonic clock reading. - * - * The monotonic clock reading exists only in [Time] values. It is not - * a part of [Duration] values or the Unix times returned by t.Unix and - * friends. - * - * Note that the Go == operator compares not just the time instant but - * also the [Location] and the monotonic clock reading. See the - * documentation for the Time type for a discussion of equality - * testing for Time values. - * - * For debugging, the result of t.String does include the monotonic - * clock reading if present. If t != u because of different monotonic clock readings, - * that difference will be visible when printing t.String() and u.String(). - * - * # Timer Resolution - * - * [Timer] resolution varies depending on the Go runtime, the operating system - * and the underlying hardware. - * On Unix, the resolution is ~1ms. - * On Windows version 1803 and newer, the resolution is ~0.5ms. - * On older Windows versions, the default resolution is ~16ms, but - * a higher resolution may be requested using [golang.org/x/sys/windows.TimeBeginPeriod]. - */ -namespace time { - interface Time { + interface AuthOrigin { /** - * String returns the time formatted using the format string - * - * ``` - * "2006-01-02 15:04:05.999999999 -0700 MST" - * ``` - * - * If the time has a monotonic clock reading, the returned string - * includes a final field "m=±", where value is the monotonic - * clock reading formatted as a decimal number of seconds. - * - * The returned string is meant for debugging; for a stable serialized - * representation, use t.MarshalText, t.MarshalBinary, or t.Format - * with an explicit format string. + * SetRecordRef updates the "recordRef" record field value. */ - string(): string + setRecordRef(recordId: string): void } - interface Time { + interface AuthOrigin { /** - * GoString implements [fmt.GoStringer] and formats t to be printed in Go source - * code. + * Fingerprint returns the "fingerprint" record field value. */ - goString(): string + fingerprint(): string } - interface Time { + interface AuthOrigin { /** - * Format returns a textual representation of the time value formatted according - * to the layout defined by the argument. See the documentation for the - * constant called [Layout] to see how to represent the layout format. - * - * The executable example for [Time.Format] demonstrates the working - * of the layout string in detail and is a good reference. + * SetFingerprint updates the "fingerprint" record field value. */ - format(layout: string): string + setFingerprint(fingerprint: string): void } - interface Time { + interface AuthOrigin { /** - * AppendFormat is like [Time.Format] but appends the textual - * representation to b and returns the extended buffer. + * Created returns the "created" record field value. */ - appendFormat(b: string|Array, layout: string): string|Array - } - /** - * A Time represents an instant in time with nanosecond precision. - * - * Programs using times should typically store and pass them as values, - * not pointers. That is, time variables and struct fields should be of - * type [time.Time], not *time.Time. - * - * A Time value can be used by multiple goroutines simultaneously except - * that the methods [Time.GobDecode], [Time.UnmarshalBinary], [Time.UnmarshalJSON] and - * [Time.UnmarshalText] are not concurrency-safe. - * - * Time instants can be compared using the [Time.Before], [Time.After], and [Time.Equal] methods. - * The [Time.Sub] method subtracts two instants, producing a [Duration]. - * The [Time.Add] method adds a Time and a Duration, producing a Time. - * - * The zero value of type Time is January 1, year 1, 00:00:00.000000000 UTC. - * As this time is unlikely to come up in practice, the [Time.IsZero] method gives - * a simple way of detecting a time that has not been initialized explicitly. - * - * Each time has an associated [Location]. The methods [Time.Local], [Time.UTC], and Time.In return a - * Time with a specific Location. Changing the Location of a Time value with - * these methods does not change the actual instant it represents, only the time - * zone in which to interpret it. - * - * Representations of a Time value saved by the [Time.GobEncode], [Time.MarshalBinary], - * [Time.MarshalJSON], and [Time.MarshalText] methods store the [Time.Location]'s offset, but not - * the location name. They therefore lose information about Daylight Saving Time. - * - * In addition to the required “wall clock” reading, a Time may contain an optional - * reading of the current process's monotonic clock, to provide additional precision - * for comparison or subtraction. - * See the “Monotonic Clocks” section in the package documentation for details. - * - * Note that the Go == operator compares not just the time instant but also the - * Location and the monotonic clock reading. Therefore, Time values should not - * be used as map or database keys without first guaranteeing that the - * identical Location has been set for all values, which can be achieved - * through use of the UTC or Local method, and that the monotonic clock reading - * has been stripped by setting t = t.Round(0). In general, prefer t.Equal(u) - * to t == u, since t.Equal uses the most accurate comparison available and - * correctly handles the case when only one of its arguments has a monotonic - * clock reading. - */ - interface Time { + created(): types.DateTime } - interface Time { + interface AuthOrigin { /** - * After reports whether the time instant t is after u. + * Updated returns the "updated" record field value. */ - after(u: Time): boolean + updated(): types.DateTime } - interface Time { + interface BaseApp { /** - * Before reports whether the time instant t is before u. + * FindAllAuthOriginsByRecord returns all AuthOrigin models linked to the provided auth record (in DESC order). */ - before(u: Time): boolean + findAllAuthOriginsByRecord(authRecord: Record): Array<(AuthOrigin | undefined)> } - interface Time { + interface BaseApp { /** - * Compare compares the time instant t with u. If t is before u, it returns -1; - * if t is after u, it returns +1; if they're the same, it returns 0. + * FindAllAuthOriginsByCollection returns all AuthOrigin models linked to the provided collection (in DESC order). */ - compare(u: Time): number + findAllAuthOriginsByCollection(collection: Collection): Array<(AuthOrigin | undefined)> } - interface Time { + interface BaseApp { /** - * Equal reports whether t and u represent the same time instant. - * Two times can be equal even if they are in different locations. - * For example, 6:00 +0200 and 4:00 UTC are Equal. - * See the documentation on the Time type for the pitfalls of using == with - * Time values; most code should use Equal instead. + * FindAuthOriginById returns a single AuthOrigin model by its id. */ - equal(u: Time): boolean + findAuthOriginById(id: string): (AuthOrigin) } - interface Time { + interface BaseApp { /** - * IsZero reports whether t represents the zero time instant, - * January 1, year 1, 00:00:00 UTC. + * FindAuthOriginByRecordAndFingerprint returns a single AuthOrigin model + * by its authRecord relation and fingerprint. */ - isZero(): boolean + findAuthOriginByRecordAndFingerprint(authRecord: Record, fingerprint: string): (AuthOrigin) } - interface Time { + interface BaseApp { /** - * Date returns the year, month, and day in which t occurs. + * DeleteAllAuthOriginsByRecord deletes all AuthOrigin models associated with the provided record. + * + * Returns a combined error with the failed deletes. */ - date(): [number, Month, number] + deleteAllAuthOriginsByRecord(authRecord: Record): void } - interface Time { + /** + * FilesManager defines an interface with common methods that files manager models should implement. + */ + interface FilesManager { + [key:string]: any; /** - * Year returns the year in which t occurs. + * BaseFilesPath returns the storage dir path used by the interface instance. */ - year(): number + baseFilesPath(): string } - interface Time { - /** - * Month returns the month of the year specified by t. - */ - month(): Month + /** + * DBConnectFunc defines a database connection initialization function. + */ + interface DBConnectFunc {(dbPath: string): (dbx.DB) } + /** + * BaseAppConfig defines a BaseApp configuration option + */ + interface BaseAppConfig { + dbConnect: DBConnectFunc + dataDir: string + encryptionEnv: string + queryTimeout: time.Duration + dataMaxOpenConns: number + dataMaxIdleConns: number + auxMaxOpenConns: number + auxMaxIdleConns: number + isDev: boolean } - interface Time { + /** + * BaseApp implements CoreApp and defines the base PocketBase app structure. + */ + interface BaseApp { + } + interface newBaseApp { /** - * Day returns the day of the month specified by t. + * NewBaseApp creates and returns a new BaseApp instance + * configured with the provided arguments. + * + * To initialize the app, you need to call `app.Bootstrap()`. */ - day(): number + (config: BaseAppConfig): (BaseApp) } - interface Time { + interface BaseApp { /** - * Weekday returns the day of the week specified by t. + * UnsafeWithoutHooks returns a shallow copy of the current app WITHOUT any registered hooks. + * + * NB! Note that using the returned app instance may cause data integrity errors + * since the Record validations and data normalizations (including files uploads) + * rely on the app hooks to work. */ - weekday(): Weekday + unsafeWithoutHooks(): App } - interface Time { + interface BaseApp { /** - * ISOWeek returns the ISO 8601 year and week number in which t occurs. - * Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to - * week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1 - * of year n+1. + * Logger returns the default app logger. + * + * If the application is not bootstrapped yet, fallbacks to slog.Default(). */ - isoWeek(): [number, number] + logger(): (slog.Logger) } - interface Time { + interface BaseApp { /** - * Clock returns the hour, minute, and second within the day specified by t. + * TxInfo returns the transaction associated with the current app instance (if any). + * + * Could be used if you want to execute indirectly a function after + * the related app transaction completes using `app.TxInfo().OnAfterFunc(callback)`. */ - clock(): [number, number, number] + txInfo(): (TxAppInfo) } - interface Time { + interface BaseApp { /** - * Hour returns the hour within the day specified by t, in the range [0, 23]. + * IsTransactional checks if the current app instance is part of a transaction. */ - hour(): number + isTransactional(): boolean } - interface Time { + interface BaseApp { /** - * Minute returns the minute offset within the hour specified by t, in the range [0, 59]. + * IsBootstrapped checks if the application was initialized + * (aka. whether Bootstrap() was called). */ - minute(): number + isBootstrapped(): boolean } - interface Time { + interface BaseApp { /** - * Second returns the second offset within the minute specified by t, in the range [0, 59]. + * Bootstrap initializes the application + * (aka. create data dir, open db connections, load settings, etc.). + * + * It will call ResetBootstrapState() if the application was already bootstrapped. */ - second(): number + bootstrap(): void } - interface Time { + interface closer { + [key:string]: any; + close(): void + } + interface BaseApp { /** - * Nanosecond returns the nanosecond offset within the second specified by t, - * in the range [0, 999999999]. + * ResetBootstrapState releases the initialized core app resources + * (closing db connections, stopping cron ticker, etc.). */ - nanosecond(): number + resetBootstrapState(): void } - interface Time { + interface BaseApp { /** - * YearDay returns the day of the year specified by t, in the range [1,365] for non-leap years, - * and [1,366] in leap years. + * DB returns the default app data.db builder instance. + * + * To minimize SQLITE_BUSY errors, it automatically routes the + * SELECT queries to the underlying concurrent db pool and everything + * else to the nonconcurrent one. + * + * For more finer control over the used connections pools you can + * call directly ConcurrentDB() or NonconcurrentDB(). */ - yearDay(): number + db(): dbx.Builder } - /** - * A Duration represents the elapsed time between two instants - * as an int64 nanosecond count. The representation limits the - * largest representable duration to approximately 290 years. - */ - interface Duration extends Number{} - interface Duration { + interface BaseApp { /** - * String returns a string representing the duration in the form "72h3m0.5s". - * Leading zero units are omitted. As a special case, durations less than one - * second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure - * that the leading digit is non-zero. The zero duration formats as 0s. + * ConcurrentDB returns the concurrent app data.db builder instance. + * + * This method is used mainly internally for executing db read + * operations in a concurrent/non-blocking manner. + * + * Most users should use simply DB() as it will automatically + * route the query execution to ConcurrentDB() or NonconcurrentDB(). + * + * In a transaction the ConcurrentDB() and NonconcurrentDB() refer to the same *dbx.TX instance. */ - string(): string + concurrentDB(): dbx.Builder } - interface Duration { + interface BaseApp { /** - * Nanoseconds returns the duration as an integer nanosecond count. + * NonconcurrentDB returns the nonconcurrent app data.db builder instance. + * + * The returned db instance is limited only to a single open connection, + * meaning that it can process only 1 db operation at a time (other queries queue up). + * + * This method is used mainly internally and in the tests to execute write + * (save/delete) db operations as it helps with minimizing the SQLITE_BUSY errors. + * + * Most users should use simply DB() as it will automatically + * route the query execution to ConcurrentDB() or NonconcurrentDB(). + * + * In a transaction the ConcurrentDB() and NonconcurrentDB() refer to the same *dbx.TX instance. */ - nanoseconds(): number + nonconcurrentDB(): dbx.Builder } - interface Duration { + interface BaseApp { /** - * Microseconds returns the duration as an integer microsecond count. + * AuxDB returns the app auxiliary.db builder instance. + * + * To minimize SQLITE_BUSY errors, it automatically routes the + * SELECT queries to the underlying concurrent db pool and everything + * else to the nonconcurrent one. + * + * For more finer control over the used connections pools you can + * call directly AuxConcurrentDB() or AuxNonconcurrentDB(). */ - microseconds(): number + auxDB(): dbx.Builder } - interface Duration { + interface BaseApp { /** - * Milliseconds returns the duration as an integer millisecond count. + * AuxConcurrentDB returns the concurrent app auxiliary.db builder instance. + * + * This method is used mainly internally for executing db read + * operations in a concurrent/non-blocking manner. + * + * Most users should use simply AuxDB() as it will automatically + * route the query execution to AuxConcurrentDB() or AuxNonconcurrentDB(). + * + * In a transaction the AuxConcurrentDB() and AuxNonconcurrentDB() refer to the same *dbx.TX instance. */ - milliseconds(): number + auxConcurrentDB(): dbx.Builder } - interface Duration { + interface BaseApp { /** - * Seconds returns the duration as a floating point number of seconds. + * AuxNonconcurrentDB returns the nonconcurrent app auxiliary.db builder instance. + * + * The returned db instance is limited only to a single open connection, + * meaning that it can process only 1 db operation at a time (other queries queue up). + * + * This method is used mainly internally and in the tests to execute write + * (save/delete) db operations as it helps with minimizing the SQLITE_BUSY errors. + * + * Most users should use simply AuxDB() as it will automatically + * route the query execution to AuxConcurrentDB() or AuxNonconcurrentDB(). + * + * In a transaction the AuxConcurrentDB() and AuxNonconcurrentDB() refer to the same *dbx.TX instance. */ - seconds(): number + auxNonconcurrentDB(): dbx.Builder } - interface Duration { + interface BaseApp { /** - * Minutes returns the duration as a floating point number of minutes. + * DataDir returns the app data directory path. */ - minutes(): number + dataDir(): string } - interface Duration { + interface BaseApp { /** - * Hours returns the duration as a floating point number of hours. + * EncryptionEnv returns the name of the app secret env key + * (currently used primarily for optional settings encryption but this may change in the future). */ - hours(): number + encryptionEnv(): string } - interface Duration { + interface BaseApp { /** - * Truncate returns the result of rounding d toward zero to a multiple of m. - * If m <= 0, Truncate returns d unchanged. + * IsDev returns whether the app is in dev mode. + * + * When enabled logs, executed sql statements, etc. are printed to the stderr. */ - truncate(m: Duration): Duration + isDev(): boolean } - interface Duration { + interface BaseApp { /** - * Round returns the result of rounding d to the nearest multiple of m. - * The rounding behavior for halfway values is to round away from zero. - * If the result exceeds the maximum (or minimum) - * value that can be stored in a [Duration], - * Round returns the maximum (or minimum) duration. - * If m <= 0, Round returns d unchanged. + * Settings returns the loaded app settings. */ - round(m: Duration): Duration + settings(): (Settings) } - interface Duration { + interface BaseApp { /** - * Abs returns the absolute value of d. - * As a special case, [math.MinInt64] is converted to [math.MaxInt64]. + * Store returns the app runtime store. */ - abs(): Duration + store(): (store.Store) } - interface Time { + interface BaseApp { /** - * Add returns the time t+d. + * Cron returns the app cron instance. */ - add(d: Duration): Time + cron(): (cron.Cron) } - interface Time { + interface BaseApp { /** - * Sub returns the duration t-u. If the result exceeds the maximum (or minimum) - * value that can be stored in a [Duration], the maximum (or minimum) duration - * will be returned. - * To compute t-d for a duration d, use t.Add(-d). + * SubscriptionsBroker returns the app realtime subscriptions broker instance. */ - sub(u: Time): Duration + subscriptionsBroker(): (subscriptions.Broker) } - interface Time { + interface BaseApp { /** - * AddDate returns the time corresponding to adding the - * given number of years, months, and days to t. - * For example, AddDate(-1, 2, 3) applied to January 1, 2011 - * returns March 4, 2010. - * - * Note that dates are fundamentally coupled to timezones, and calendrical - * periods like days don't have fixed durations. AddDate uses the Location of - * the Time value to determine these durations. That means that the same - * AddDate arguments can produce a different shift in absolute time depending on - * the base Time value and its Location. For example, AddDate(0, 0, 1) applied - * to 12:00 on March 27 always returns 12:00 on March 28. At some locations and - * in some years this is a 24 hour shift. In others it's a 23 hour shift due to - * daylight savings time transitions. - * - * AddDate normalizes its result in the same way that Date does, - * so, for example, adding one month to October 31 yields - * December 1, the normalized form for November 31. + * NewMailClient creates and returns a new SMTP or Sendmail client + * based on the current app settings. */ - addDate(years: number, months: number, days: number): Time + newMailClient(): mailer.Mailer } - interface Time { + interface BaseApp { /** - * UTC returns t with the location set to UTC. + * NewFilesystem creates a new local or S3 filesystem instance + * for managing regular app files (ex. record uploads) + * based on the current app settings. + * + * NB! Make sure to call Close() on the returned result + * after you are done working with it. */ - utc(): Time + newFilesystem(): (filesystem.System) } - interface Time { + interface BaseApp { /** - * Local returns t with the location set to local time. + * NewBackupsFilesystem creates a new local or S3 filesystem instance + * for managing app backups based on the current app settings. + * + * NB! Make sure to call Close() on the returned result + * after you are done working with it. */ - local(): Time + newBackupsFilesystem(): (filesystem.System) } - interface Time { + interface BaseApp { /** - * In returns a copy of t representing the same time instant, but - * with the copy's location information set to loc for display - * purposes. + * Restart restarts (aka. replaces) the current running application process. * - * In panics if loc is nil. + * NB! It relies on execve which is supported only on UNIX based systems. */ - in(loc: Location): Time + restart(): void } - interface Time { + interface BaseApp { /** - * Location returns the time zone information associated with t. + * RunSystemMigrations applies all new migrations registered in the [core.SystemMigrations] list. */ - location(): (Location) + runSystemMigrations(): void } - interface Time { + interface BaseApp { /** - * Zone computes the time zone in effect at time t, returning the abbreviated - * name of the zone (such as "CET") and its offset in seconds east of UTC. + * RunAppMigrations applies all new migrations registered in the [CoreAppMigrations] list. */ - zone(): [string, number] + runAppMigrations(): void } - interface Time { + interface BaseApp { /** - * ZoneBounds returns the bounds of the time zone in effect at time t. - * The zone begins at start and the next zone begins at end. - * If the zone begins at the beginning of time, start will be returned as a zero Time. - * If the zone goes on forever, end will be returned as a zero Time. - * The Location of the returned times will be the same as t. + * RunAllMigrations applies all system and app migrations + * (aka. from both [core.SystemMigrations] and [CoreAppMigrations]). */ - zoneBounds(): [Time, Time] + runAllMigrations(): void } - interface Time { - /** - * Unix returns t as a Unix time, the number of seconds elapsed - * since January 1, 1970 UTC. The result does not depend on the - * location associated with t. - * Unix-like operating systems often record time as a 32-bit - * count of seconds, but since the method here returns a 64-bit - * value it is valid for billions of years into the past or future. - */ - unix(): number + interface BaseApp { + onBootstrap(): (hook.Hook) } - interface Time { - /** - * UnixMilli returns t as a Unix time, the number of milliseconds elapsed since - * January 1, 1970 UTC. The result is undefined if the Unix time in - * milliseconds cannot be represented by an int64 (a date more than 292 million - * years before or after 1970). The result does not depend on the - * location associated with t. - */ - unixMilli(): number + interface BaseApp { + onServe(): (hook.Hook) } - interface Time { - /** - * UnixMicro returns t as a Unix time, the number of microseconds elapsed since - * January 1, 1970 UTC. The result is undefined if the Unix time in - * microseconds cannot be represented by an int64 (a date before year -290307 or - * after year 294246). The result does not depend on the location associated - * with t. - */ - unixMicro(): number + interface BaseApp { + onTerminate(): (hook.Hook) } - interface Time { - /** - * UnixNano returns t as a Unix time, the number of nanoseconds elapsed - * since January 1, 1970 UTC. The result is undefined if the Unix time - * in nanoseconds cannot be represented by an int64 (a date before the year - * 1678 or after 2262). Note that this means the result of calling UnixNano - * on the zero Time is undefined. The result does not depend on the - * location associated with t. - */ - unixNano(): number + interface BaseApp { + onBackupCreate(): (hook.Hook) } - interface Time { - /** - * MarshalBinary implements the encoding.BinaryMarshaler interface. - */ - marshalBinary(): string|Array + interface BaseApp { + onBackupRestore(): (hook.Hook) } - interface Time { - /** - * UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. - */ - unmarshalBinary(data: string|Array): void + interface BaseApp { + onModelCreate(...tags: string[]): (hook.TaggedHook) } - interface Time { - /** - * GobEncode implements the gob.GobEncoder interface. - */ - gobEncode(): string|Array + interface BaseApp { + onModelCreateExecute(...tags: string[]): (hook.TaggedHook) } - interface Time { - /** - * GobDecode implements the gob.GobDecoder interface. - */ - gobDecode(data: string|Array): void + interface BaseApp { + onModelAfterCreateSuccess(...tags: string[]): (hook.TaggedHook) } - interface Time { - /** - * MarshalJSON implements the [json.Marshaler] interface. - * The time is a quoted string in the RFC 3339 format with sub-second precision. - * If the timestamp cannot be represented as valid RFC 3339 - * (e.g., the year is out of range), then an error is reported. - */ - marshalJSON(): string|Array + interface BaseApp { + onModelAfterCreateError(...tags: string[]): (hook.TaggedHook) } - interface Time { - /** - * UnmarshalJSON implements the [json.Unmarshaler] interface. - * The time must be a quoted string in the RFC 3339 format. - */ - unmarshalJSON(data: string|Array): void + interface BaseApp { + onModelUpdate(...tags: string[]): (hook.TaggedHook) } - interface Time { - /** - * MarshalText implements the [encoding.TextMarshaler] interface. - * The time is formatted in RFC 3339 format with sub-second precision. - * If the timestamp cannot be represented as valid RFC 3339 - * (e.g., the year is out of range), then an error is reported. - */ - marshalText(): string|Array + interface BaseApp { + onModelUpdateExecute(...tags: string[]): (hook.TaggedHook) } - interface Time { - /** - * UnmarshalText implements the [encoding.TextUnmarshaler] interface. - * The time must be in the RFC 3339 format. - */ - unmarshalText(data: string|Array): void + interface BaseApp { + onModelAfterUpdateSuccess(...tags: string[]): (hook.TaggedHook) } - interface Time { - /** - * IsDST reports whether the time in the configured location is in Daylight Savings Time. - */ - isDST(): boolean + interface BaseApp { + onModelAfterUpdateError(...tags: string[]): (hook.TaggedHook) } - interface Time { - /** - * Truncate returns the result of rounding t down to a multiple of d (since the zero time). - * If d <= 0, Truncate returns t stripped of any monotonic clock reading but otherwise unchanged. - * - * Truncate operates on the time as an absolute duration since the - * zero time; it does not operate on the presentation form of the - * time. Thus, Truncate(Hour) may return a time with a non-zero - * minute, depending on the time's Location. - */ - truncate(d: Duration): Time + interface BaseApp { + onModelValidate(...tags: string[]): (hook.TaggedHook) } - interface Time { - /** - * Round returns the result of rounding t to the nearest multiple of d (since the zero time). - * The rounding behavior for halfway values is to round up. - * If d <= 0, Round returns t stripped of any monotonic clock reading but otherwise unchanged. - * - * Round operates on the time as an absolute duration since the - * zero time; it does not operate on the presentation form of the - * time. Thus, Round(Hour) may return a time with a non-zero - * minute, depending on the time's Location. - */ - round(d: Duration): Time + interface BaseApp { + onModelDelete(...tags: string[]): (hook.TaggedHook) } -} - -/** - * Package context defines the Context type, which carries deadlines, - * cancellation signals, and other request-scoped values across API boundaries - * and between processes. - * - * Incoming requests to a server should create a [Context], and outgoing - * calls to servers should accept a Context. The chain of function - * calls between them must propagate the Context, optionally replacing - * it with a derived Context created using [WithCancel], [WithDeadline], - * [WithTimeout], or [WithValue]. When a Context is canceled, all - * Contexts derived from it are also canceled. - * - * The [WithCancel], [WithDeadline], and [WithTimeout] functions take a - * Context (the parent) and return a derived Context (the child) and a - * [CancelFunc]. Calling the CancelFunc cancels the child and its - * children, removes the parent's reference to the child, and stops - * any associated timers. Failing to call the CancelFunc leaks the - * child and its children until the parent is canceled or the timer - * fires. The go vet tool checks that CancelFuncs are used on all - * control-flow paths. - * - * The [WithCancelCause] function returns a [CancelCauseFunc], which - * takes an error and records it as the cancellation cause. Calling - * [Cause] on the canceled context or any of its children retrieves - * the cause. If no cause is specified, Cause(ctx) returns the same - * value as ctx.Err(). - * - * Programs that use Contexts should follow these rules to keep interfaces - * consistent across packages and enable static analysis tools to check context - * propagation: - * - * Do not store Contexts inside a struct type; instead, pass a Context - * explicitly to each function that needs it. The Context should be the first - * parameter, typically named ctx: - * - * ``` - * func DoSomething(ctx context.Context, arg Arg) error { - * // ... use ctx ... - * } - * ``` - * - * Do not pass a nil [Context], even if a function permits it. Pass [context.TODO] - * if you are unsure about which Context to use. - * - * Use context Values only for request-scoped data that transits processes and - * APIs, not for passing optional parameters to functions. - * - * The same Context may be passed to functions running in different goroutines; - * Contexts are safe for simultaneous use by multiple goroutines. - * - * See https://blog.golang.org/context for example code for a server that uses - * Contexts. - */ -namespace context { - /** - * A Context carries a deadline, a cancellation signal, and other values across - * API boundaries. - * - * Context's methods may be called by multiple goroutines simultaneously. - */ - interface Context { - [key:string]: any; - /** - * Deadline returns the time when work done on behalf of this context - * should be canceled. Deadline returns ok==false when no deadline is - * set. Successive calls to Deadline return the same results. - */ - deadline(): [time.Time, boolean] + interface BaseApp { + onModelDeleteExecute(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onModelAfterDeleteSuccess(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onModelAfterDeleteError(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordEnrich(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordValidate(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordCreate(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordCreateExecute(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordAfterCreateSuccess(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordAfterCreateError(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordUpdate(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordUpdateExecute(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordAfterUpdateSuccess(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordAfterUpdateError(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordDelete(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordDeleteExecute(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordAfterDeleteSuccess(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordAfterDeleteError(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onCollectionValidate(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onCollectionCreate(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onCollectionCreateExecute(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onCollectionAfterCreateSuccess(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onCollectionAfterCreateError(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onCollectionUpdate(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onCollectionUpdateExecute(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onCollectionAfterUpdateSuccess(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onCollectionAfterUpdateError(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onCollectionDelete(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onCollectionDeleteExecute(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onCollectionAfterDeleteSuccess(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onCollectionAfterDeleteError(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onMailerSend(): (hook.Hook) + } + interface BaseApp { + onMailerRecordPasswordResetSend(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onMailerRecordVerificationSend(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onMailerRecordEmailChangeSend(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onMailerRecordOTPSend(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onMailerRecordAuthAlertSend(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRealtimeConnectRequest(): (hook.Hook) + } + interface BaseApp { + onRealtimeMessageSend(): (hook.Hook) + } + interface BaseApp { + onRealtimeSubscribeRequest(): (hook.Hook) + } + interface BaseApp { + onSettingsListRequest(): (hook.Hook) + } + interface BaseApp { + onSettingsUpdateRequest(): (hook.Hook) + } + interface BaseApp { + onSettingsReload(): (hook.Hook) + } + interface BaseApp { + onFileDownloadRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onFileTokenRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordAuthRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordAuthWithPasswordRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordAuthWithOAuth2Request(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordAuthRefreshRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordRequestPasswordResetRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordConfirmPasswordResetRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordRequestVerificationRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordConfirmVerificationRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordRequestEmailChangeRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordConfirmEmailChangeRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordRequestOTPRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordAuthWithOTPRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordsListRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordViewRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordCreateRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordUpdateRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onRecordDeleteRequest(...tags: string[]): (hook.TaggedHook) + } + interface BaseApp { + onCollectionsListRequest(): (hook.Hook) + } + interface BaseApp { + onCollectionViewRequest(): (hook.Hook) + } + interface BaseApp { + onCollectionCreateRequest(): (hook.Hook) + } + interface BaseApp { + onCollectionUpdateRequest(): (hook.Hook) + } + interface BaseApp { + onCollectionDeleteRequest(): (hook.Hook) + } + interface BaseApp { + onCollectionsImportRequest(): (hook.Hook) + } + interface BaseApp { + onBatchRequest(): (hook.Hook) + } + interface BaseApp { /** - * Done returns a channel that's closed when work done on behalf of this - * context should be canceled. Done may return nil if this context can - * never be canceled. Successive calls to Done return the same value. - * The close of the Done channel may happen asynchronously, - * after the cancel function returns. + * CreateBackup creates a new backup of the current app pb_data directory. * - * WithCancel arranges for Done to be closed when cancel is called; - * WithDeadline arranges for Done to be closed when the deadline - * expires; WithTimeout arranges for Done to be closed when the timeout - * elapses. + * If name is empty, it will be autogenerated. + * If backup with the same name exists, the new backup file will replace it. * - * Done is provided for use in select statements: + * The backup is executed within a transaction, meaning that new writes + * will be temporary "blocked" until the backup file is generated. * - * // Stream generates values with DoSomething and sends them to out - * // until DoSomething returns an error or ctx.Done is closed. - * func Stream(ctx context.Context, out chan<- Value) error { - * for { - * v, err := DoSomething(ctx) - * if err != nil { - * return err - * } - * select { - * case <-ctx.Done(): - * return ctx.Err() - * case out <- v: - * } - * } - * } + * To safely perform the backup, it is recommended to have free disk space + * for at least 2x the size of the pb_data directory. * - * See https://blog.golang.org/pipelines for more examples of how to use - * a Done channel for cancellation. - */ - done(): undefined - /** - * If Done is not yet closed, Err returns nil. - * If Done is closed, Err returns a non-nil error explaining why: - * Canceled if the context was canceled - * or DeadlineExceeded if the context's deadline passed. - * After Err returns a non-nil error, successive calls to Err return the same error. + * By default backups are stored in pb_data/backups + * (the backups directory itself is excluded from the generated backup). + * + * When using S3 storage for the uploaded collection files, you have to + * take care manually to backup those since they are not part of the pb_data. + * + * Backups can be stored on S3 if it is configured in app.Settings().Backups. */ - err(): void + createBackup(ctx: context.Context, name: string): void + } + interface BaseApp { /** - * Value returns the value associated with this context for key, or nil - * if no value is associated with key. Successive calls to Value with - * the same key returns the same result. + * RestoreBackup restores the backup with the specified name and restarts + * the current running application process. * - * Use context values only for request-scoped data that transits - * processes and API boundaries, not for passing optional parameters to - * functions. + * NB! This feature is experimental and currently is expected to work only on UNIX based systems. * - * A key identifies a specific value in a Context. Functions that wish - * to store values in Context typically allocate a key in a global - * variable then use that key as the argument to context.WithValue and - * Context.Value. A key can be any type that supports equality; - * packages should define keys as an unexported type to avoid - * collisions. + * To safely perform the restore it is recommended to have free disk space + * for at least 2x the size of the restored pb_data backup. * - * Packages that define a Context key should provide type-safe accessors - * for the values stored using that key: + * The performed steps are: * + * 1. Download the backup with the specified name in a temp location + * ``` + * (this is in case of S3; otherwise it creates a temp copy of the zip) * ``` - * // Package user defines a User type that's stored in Contexts. - * package user * - * import "context" + * 2. Extract the backup in a temp directory inside the app "pb_data" + * ``` + * (eg. "pb_data/.pb_temp_to_delete/pb_restore"). + * ``` * - * // User is the type of value stored in the Contexts. - * type User struct {...} + * 3. Move the current app "pb_data" content (excluding the local backups and the special temp dir) + * ``` + * under another temp sub dir that will be deleted on the next app start up + * (eg. "pb_data/.pb_temp_to_delete/old_pb_data"). + * This is because on some environments it may not be allowed + * to delete the currently open "pb_data" files. + * ``` * - * // key is an unexported type for keys defined in this package. - * // This prevents collisions with keys defined in other packages. - * type key int + * 4. Move the extracted dir content to the app "pb_data". * - * // userKey is the key for user.User values in Contexts. It is - * // unexported; clients use user.NewContext and user.FromContext - * // instead of using this key directly. - * var userKey key + * 5. Restart the app (on successful app bootstap it will also remove the old pb_data). * - * // NewContext returns a new Context that carries value u. - * func NewContext(ctx context.Context, u *User) context.Context { - * return context.WithValue(ctx, userKey, u) - * } + * If a failure occure during the restore process the dir changes are reverted. + * If for whatever reason the revert is not possible, it panics. * - * // FromContext returns the User value stored in ctx, if any. - * func FromContext(ctx context.Context) (*User, bool) { - * u, ok := ctx.Value(userKey).(*User) - * return u, ok - * } - * ``` + * Note that if your pb_data has custom network mounts as subdirectories, then + * it is possible the restore to fail during the `os.Rename` operations + * (see https://github.com/pocketbase/pocketbase/issues/4647). */ - value(key: any): any + restoreBackup(ctx: context.Context, name: string): void + } + interface BaseApp { + /** + * ImportCollectionsByMarshaledJSON is the same as [ImportCollections] + * but accept marshaled json array as import data (usually used for the autogenerated snapshots). + */ + importCollectionsByMarshaledJSON(rawSliceOfMaps: string|Array, deleteMissing: boolean): void + } + interface BaseApp { + /** + * ImportCollections imports the provided collections data in a single transaction. + * + * For existing matching collections, the imported data is unmarshaled on top of the existing model. + * + * NB! If deleteMissing is true, ALL NON-SYSTEM COLLECTIONS AND SCHEMA FIELDS, + * that are not present in the imported configuration, WILL BE DELETED + * (this includes their related records data). + */ + importCollections(toImport: Array<_TygojaDict>, deleteMissing: boolean): void } -} - -/** - * Package io provides basic interfaces to I/O primitives. - * Its primary job is to wrap existing implementations of such primitives, - * such as those in package os, into shared public interfaces that - * abstract the functionality, plus some other related primitives. - * - * Because these interfaces and primitives wrap lower-level operations with - * various implementations, unless otherwise informed clients should not - * assume they are safe for parallel execution. - */ -namespace io { /** - * Reader is the interface that wraps the basic Read method. - * - * Read reads up to len(p) bytes into p. It returns the number of bytes - * read (0 <= n <= len(p)) and any error encountered. Even if Read - * returns n < len(p), it may use all of p as scratch space during the call. - * If some data is available but not len(p) bytes, Read conventionally - * returns what is available instead of waiting for more. - * - * When Read encounters an error or end-of-file condition after - * successfully reading n > 0 bytes, it returns the number of - * bytes read. It may return the (non-nil) error from the same call - * or return the error (and n == 0) from a subsequent call. - * An instance of this general case is that a Reader returning - * a non-zero number of bytes at the end of the input stream may - * return either err == EOF or err == nil. The next Read should - * return 0, EOF. - * - * Callers should always process the n > 0 bytes returned before - * considering the error err. Doing so correctly handles I/O errors - * that happen after reading some bytes and also both of the - * allowed EOF behaviors. - * - * If len(p) == 0, Read should always return n == 0. It may return a - * non-nil error if some error condition is known, such as EOF. - * - * Implementations of Read are discouraged from returning a - * zero byte count with a nil error, except when len(p) == 0. - * Callers should treat a return of 0 and nil as indicating that - * nothing happened; in particular it does not indicate EOF. - * - * Implementations must not retain p. + * @todo experiment eventually replacing the rules *string with a struct? */ - interface Reader { - [key:string]: any; - read(p: string|Array): number + type _saLDmEe = BaseModel + interface baseCollection extends _saLDmEe { + listRule?: string + viewRule?: string + createRule?: string + updateRule?: string + deleteRule?: string + /** + * RawOptions represents the raw serialized collection option loaded from the DB. + * NB! This field shouldn't be modified manually. It is automatically updated + * with the collection type specific option before save. + */ + rawOptions: types.JSONRaw + name: string + type: string + fields: FieldsList + indexes: types.JSONArray + created: types.DateTime + updated: types.DateTime + /** + * System prevents the collection rename, deletion and rules change. + * It is used primarily for internal purposes for collections like "_superusers", "_externalAuths", etc. + */ + system: boolean } /** - * Writer is the interface that wraps the basic Write method. - * - * Write writes len(p) bytes from p to the underlying data stream. - * It returns the number of bytes written from p (0 <= n <= len(p)) - * and any error encountered that caused the write to stop early. - * Write must return a non-nil error if it returns n < len(p). - * Write must not modify the slice data, even temporarily. - * - * Implementations must not retain p. + * Collection defines the table, fields and various options related to a set of records. */ - interface Writer { - [key:string]: any; - write(p: string|Array): number - } - /** - * ReadSeekCloser is the interface that groups the basic Read, Seek and Close - * methods. - */ - interface ReadSeekCloser { - [key:string]: any; + type _stottJv = baseCollection&collectionAuthOptions&collectionViewOptions + interface Collection extends _stottJv { } -} - -/** - * Package fs defines basic interfaces to a file system. - * A file system can be provided by the host operating system - * but also by other packages. - * - * See the [testing/fstest] package for support with testing - * implementations of file systems. - */ -namespace fs { - /** - * An FS provides access to a hierarchical file system. - * - * The FS interface is the minimum implementation required of the file system. - * A file system may implement additional interfaces, - * such as [ReadFileFS], to provide additional or optimized functionality. - * - * [testing/fstest.TestFS] may be used to test implementations of an FS for - * correctness. - */ - interface FS { - [key:string]: any; + interface newCollection { /** - * Open opens the named file. - * - * When Open returns an error, it should be of type *PathError - * with the Op field set to "open", the Path field set to name, - * and the Err field describing the problem. + * NewCollection initializes and returns a new Collection model with the specified type and name. * - * Open should reject attempts to open names that do not satisfy - * ValidPath(name), returning a *PathError with Err set to - * ErrInvalid or ErrNotExist. + * It also loads the minimal default configuration for the collection + * (eg. system fields, indexes, type specific options, etc.). */ - open(name: string): File - } - /** - * A File provides access to a single file. - * The File interface is the minimum implementation required of the file. - * Directory files should also implement [ReadDirFile]. - * A file may implement [io.ReaderAt] or [io.Seeker] as optimizations. - */ - interface File { - [key:string]: any; - stat(): FileInfo - read(_arg0: string|Array): number - close(): void + (typ: string, name: string, ...optId: string[]): (Collection) } - /** - * A DirEntry is an entry read from a directory - * (using the [ReadDir] function or a [ReadDirFile]'s ReadDir method). - */ - interface DirEntry { - [key:string]: any; + interface newBaseCollection { /** - * Name returns the name of the file (or subdirectory) described by the entry. - * This name is only the final element of the path (the base name), not the entire path. - * For example, Name would return "hello.go" not "home/gopher/hello.go". + * NewBaseCollection initializes and returns a new "base" Collection model. + * + * It also loads the minimal default configuration for the collection + * (eg. system fields, indexes, type specific options, etc.). */ - name(): string + (name: string, ...optId: string[]): (Collection) + } + interface newViewCollection { /** - * IsDir reports whether the entry describes a directory. + * NewViewCollection initializes and returns a new "view" Collection model. + * + * It also loads the minimal default configuration for the collection + * (eg. system fields, indexes, type specific options, etc.). */ - isDir(): boolean + (name: string, ...optId: string[]): (Collection) + } + interface newAuthCollection { /** - * Type returns the type bits for the entry. - * The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method. + * NewAuthCollection initializes and returns a new "auth" Collection model. + * + * It also loads the minimal default configuration for the collection + * (eg. system fields, indexes, type specific options, etc.). */ - type(): FileMode + (name: string, ...optId: string[]): (Collection) + } + interface Collection { /** - * Info returns the FileInfo for the file or subdirectory described by the entry. - * The returned FileInfo may be from the time of the original directory read - * or from the time of the call to Info. If the file has been removed or renamed - * since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist). - * If the entry denotes a symbolic link, Info reports the information about the link itself, - * not the link's target. + * TableName returns the Collection model SQL table name. */ - info(): FileInfo - } - /** - * A FileInfo describes a file and is returned by [Stat]. - */ - interface FileInfo { - [key:string]: any; - name(): string // base name of the file - size(): number // length in bytes for regular files; system-dependent for others - mode(): FileMode // file mode bits - modTime(): time.Time // modification time - isDir(): boolean // abbreviation for Mode().IsDir() - sys(): any // underlying data source (can return nil) - } - /** - * A FileMode represents a file's mode and permission bits. - * The bits have the same definition on all systems, so that - * information about files can be moved from one system - * to another portably. Not all bits apply to all systems. - * The only required bit is [ModeDir] for directories. - */ - interface FileMode extends Number{} - interface FileMode { - string(): string + tableName(): string } - interface FileMode { + interface Collection { /** - * IsDir reports whether m describes a directory. - * That is, it tests for the [ModeDir] bit being set in m. + * BaseFilesPath returns the storage dir path used by the collection. */ - isDir(): boolean + baseFilesPath(): string } - interface FileMode { + interface Collection { /** - * IsRegular reports whether m describes a regular file. - * That is, it tests that no mode type bits are set. + * IsBase checks if the current collection has "base" type. */ - isRegular(): boolean + isBase(): boolean } - interface FileMode { + interface Collection { /** - * Perm returns the Unix permission bits in m (m & [ModePerm]). + * IsAuth checks if the current collection has "auth" type. */ - perm(): FileMode + isAuth(): boolean } - interface FileMode { + interface Collection { /** - * Type returns type bits in m (m & [ModeType]). + * IsView checks if the current collection has "view" type. */ - type(): FileMode - } - /** - * PathError records an error and the operation and file path that caused it. - */ - interface PathError { - op: string - path: string - err: Error - } - interface PathError { - error(): string - } - interface PathError { - unwrap(): void + isView(): boolean } - interface PathError { + interface Collection { /** - * Timeout reports whether this error represents a timeout. + * IntegrityChecks toggles the current collection integrity checks (ex. checking references on delete). */ - timeout(): boolean - } - /** - * WalkDirFunc is the type of the function called by [WalkDir] to visit - * each file or directory. - * - * The path argument contains the argument to [WalkDir] as a prefix. - * That is, if WalkDir is called with root argument "dir" and finds a file - * named "a" in that directory, the walk function will be called with - * argument "dir/a". - * - * The d argument is the [DirEntry] for the named path. - * - * The error result returned by the function controls how [WalkDir] - * continues. If the function returns the special value [SkipDir], WalkDir - * skips the current directory (path if d.IsDir() is true, otherwise - * path's parent directory). If the function returns the special value - * [SkipAll], WalkDir skips all remaining files and directories. Otherwise, - * if the function returns a non-nil error, WalkDir stops entirely and - * returns that error. - * - * The err argument reports an error related to path, signaling that - * [WalkDir] will not walk into that directory. The function can decide how - * to handle that error; as described earlier, returning the error will - * cause WalkDir to stop walking the entire tree. - * - * [WalkDir] calls the function with a non-nil err argument in two cases. - * - * First, if the initial [Stat] on the root directory fails, WalkDir - * calls the function with path set to root, d set to nil, and err set to - * the error from [fs.Stat]. - * - * Second, if a directory's ReadDir method (see [ReadDirFile]) fails, WalkDir calls the - * function with path set to the directory's path, d set to an - * [DirEntry] describing the directory, and err set to the error from - * ReadDir. In this second case, the function is called twice with the - * path of the directory: the first call is before the directory read is - * attempted and has err set to nil, giving the function a chance to - * return [SkipDir] or [SkipAll] and avoid the ReadDir entirely. The second call - * is after a failed ReadDir and reports the error from ReadDir. - * (If ReadDir succeeds, there is no second call.) - * - * The differences between WalkDirFunc compared to [path/filepath.WalkFunc] are: - * - * ``` - * - The second argument has type [DirEntry] instead of [FileInfo]. - * - The function is called before reading a directory, to allow [SkipDir] - * or [SkipAll] to bypass the directory read entirely or skip all remaining - * files and directories respectively. - * - If a directory read fails, the function is called a second time - * for that directory to report the error. - * ``` - */ - interface WalkDirFunc {(path: string, d: DirEntry, err: Error): void } -} - -/** - * Package bytes implements functions for the manipulation of byte slices. - * It is analogous to the facilities of the [strings] package. - */ -namespace bytes { - /** - * A Reader implements the [io.Reader], [io.ReaderAt], [io.WriterTo], [io.Seeker], - * [io.ByteScanner], and [io.RuneScanner] interfaces by reading from - * a byte slice. - * Unlike a [Buffer], a Reader is read-only and supports seeking. - * The zero value for Reader operates like a Reader of an empty slice. - */ - interface Reader { + integrityChecks(enable: boolean): void } - interface Reader { + interface Collection { /** - * Len returns the number of bytes of the unread portion of the - * slice. + * PostScan implements the [dbx.PostScanner] interface to auto unmarshal + * the raw serialized options into the concrete type specific fields. */ - len(): number + postScan(): void } - interface Reader { + interface Collection { /** - * Size returns the original length of the underlying byte slice. - * Size is the number of bytes available for reading via [Reader.ReadAt]. - * The result is unaffected by any method calls except [Reader.Reset]. + * UnmarshalJSON implements the [json.Unmarshaler] interface. + * + * For new/"blank" Collection models it replaces the model with a factory + * instance and then unmarshal the provided data one on top of it. */ - size(): number + unmarshalJSON(b: string|Array): void } - interface Reader { + interface Collection { /** - * Read implements the [io.Reader] interface. + * MarshalJSON implements the [json.Marshaler] interface. + * + * Note that non-type related fields are ignored from the serialization + * (ex. for "view" colections the "auth" fields are skipped). */ - read(b: string|Array): number + marshalJSON(): string|Array } - interface Reader { + interface Collection { /** - * ReadAt implements the [io.ReaderAt] interface. + * String returns a string representation of the current collection. */ - readAt(b: string|Array, off: number): number + string(): string } - interface Reader { + interface Collection { /** - * ReadByte implements the [io.ByteReader] interface. + * DBExport prepares and exports the current collection data for db persistence. */ - readByte(): number + dbExport(app: App): _TygojaDict } - interface Reader { + interface Collection { /** - * UnreadByte complements [Reader.ReadByte] in implementing the [io.ByteScanner] interface. + * GetIndex returns s single Collection index expression by its name. */ - unreadByte(): void + getIndex(name: string): string } - interface Reader { + interface Collection { /** - * ReadRune implements the [io.RuneReader] interface. + * AddIndex adds a new index into the current collection. + * + * If the collection has an existing index matching the new name it will be replaced with the new one. */ - readRune(): [number, number] + addIndex(name: string, unique: boolean, columnsExpr: string, optWhereExpr: string): void } - interface Reader { + interface Collection { /** - * UnreadRune complements [Reader.ReadRune] in implementing the [io.RuneScanner] interface. + * RemoveIndex removes a single index with the specified name from the current collection. */ - unreadRune(): void + removeIndex(name: string): void } - interface Reader { + /** + * collectionAuthOptions defines the options for the "auth" type collection. + */ + interface collectionAuthOptions { /** - * Seek implements the [io.Seeker] interface. + * AuthRule could be used to specify additional record constraints + * applied after record authentication and right before returning the + * auth token response to the client. + * + * For example, to allow only verified users you could set it to + * "verified = true". + * + * Set it to empty string to allow any Auth collection record to authenticate. + * + * Set it to nil to disallow authentication altogether for the collection + * (that includes password, OAuth2, etc.). */ - seek(offset: number, whence: number): number + authRule?: string + /** + * ManageRule gives admin-like permissions to allow fully managing + * the auth record(s), eg. changing the password without requiring + * to enter the old one, directly updating the verified state and email, etc. + * + * This rule is executed in addition to the Create and Update API rules. + */ + manageRule?: string + /** + * AuthAlert defines options related to the auth alerts on new device login. + */ + authAlert: AuthAlertConfig + /** + * OAuth2 specifies whether OAuth2 auth is enabled for the collection + * and which OAuth2 providers are allowed. + */ + oauth2: OAuth2Config + /** + * PasswordAuth defines options related to the collection password authentication. + */ + passwordAuth: PasswordAuthConfig + /** + * MFA defines options related to the Multi-factor authentication (MFA). + */ + mfa: MFAConfig + /** + * OTP defines options related to the One-time password authentication (OTP). + */ + otp: OTPConfig + /** + * Various token configurations + * --- + */ + authToken: TokenConfig + passwordResetToken: TokenConfig + emailChangeToken: TokenConfig + verificationToken: TokenConfig + fileToken: TokenConfig + /** + * Default email templates + * --- + */ + verificationTemplate: EmailTemplate + resetPasswordTemplate: EmailTemplate + confirmEmailChangeTemplate: EmailTemplate } - interface Reader { + interface EmailTemplate { + subject: string + body: string + } + interface EmailTemplate { /** - * WriteTo implements the [io.WriterTo] interface. + * Validate makes EmailTemplate validatable by implementing [validation.Validatable] interface. */ - writeTo(w: io.Writer): number + validate(): void } - interface Reader { + interface EmailTemplate { /** - * Reset resets the [Reader] to be reading from b. + * Resolve replaces the placeholder parameters in the current email + * template and returns its components as ready-to-use strings. */ - reset(b: string|Array): void + resolve(placeholders: _TygojaDict): [string, string] } -} - -/** - * Package types implements some commonly used db serializable types - * like datetime, json, etc. - */ -namespace types { - /** - * JsonArray defines a slice that is safe for json and db read/write. - */ - interface JsonArray extends Array{} - interface JsonArray { + interface AuthAlertConfig { + enabled: boolean + emailTemplate: EmailTemplate + } + interface AuthAlertConfig { /** - * MarshalJSON implements the [json.Marshaler] interface. + * Validate makes AuthAlertConfig validatable by implementing [validation.Validatable] interface. */ - marshalJSON(): string|Array + validate(): void } - interface JsonArray { + interface TokenConfig { + secret: string /** - * Value implements the [driver.Valuer] interface. + * Duration specifies how long an issued token to be valid (in seconds) */ - value(): any + duration: number } - interface JsonArray { + interface TokenConfig { /** - * Scan implements [sql.Scanner] interface to scan the provided value - * into the current JsonArray[T] instance. + * Validate makes TokenConfig validatable by implementing [validation.Validatable] interface. */ - scan(value: any): void + validate(): void } - /** - * JsonMap defines a map that is safe for json and db read/write. - */ - interface JsonMap extends _TygojaDict{} - interface JsonMap { + interface TokenConfig { /** - * MarshalJSON implements the [json.Marshaler] interface. + * DurationTime returns the current Duration as [time.Duration]. */ - marshalJSON(): string|Array + durationTime(): time.Duration } - interface JsonMap { + interface OTPConfig { + enabled: boolean + /** + * Duration specifies how long the OTP to be valid (in seconds) + */ + duration: number + /** + * Length specifies the auto generated password length. + */ + length: number /** - * Get retrieves a single value from the current JsonMap. + * EmailTemplate is the default OTP email template that will be send to the auth record. * - * This helper was added primarily to assist the goja integration since custom map types - * don't have direct access to the map keys (https://pkg.go.dev/github.com/dop251/goja#hdr-Maps_with_methods). + * In addition to the system placeholders you can also make use of + * [core.EmailPlaceholderOTPId] and [core.EmailPlaceholderOTP]. */ - get(key: string): any + emailTemplate: EmailTemplate + } + interface OTPConfig { + /** + * Validate makes OTPConfig validatable by implementing [validation.Validatable] interface. + */ + validate(): void } - interface JsonMap { + interface OTPConfig { /** - * Set sets a single value in the current JsonMap. + * DurationTime returns the current Duration as [time.Duration]. + */ + durationTime(): time.Duration + } + interface MFAConfig { + enabled: boolean + /** + * Duration specifies how long an issued MFA to be valid (in seconds) + */ + duration: number + /** + * Rule is an optional field to restrict MFA only for the records that satisfy the rule. * - * This helper was added primarily to assist the goja integration since custom map types - * don't have direct access to the map keys (https://pkg.go.dev/github.com/dop251/goja#hdr-Maps_with_methods). + * Leave it empty to enable MFA for everyone. */ - set(key: string, value: any): void + rule: string } - interface JsonMap { + interface MFAConfig { /** - * Value implements the [driver.Valuer] interface. + * Validate makes MFAConfig validatable by implementing [validation.Validatable] interface. */ - value(): any + validate(): void } - interface JsonMap { + interface MFAConfig { /** - * Scan implements [sql.Scanner] interface to scan the provided value - * into the current `JsonMap` instance. + * DurationTime returns the current Duration as [time.Duration]. */ - scan(value: any): void + durationTime(): time.Duration + } + interface PasswordAuthConfig { + enabled: boolean + /** + * IdentityFields is a list of field names that could be used as + * identity during password authentication. + * + * Usually only fields that has single column UNIQUE index are accepted as values. + */ + identityFields: Array + } + interface PasswordAuthConfig { + /** + * Validate makes PasswordAuthConfig validatable by implementing [validation.Validatable] interface. + */ + validate(): void + } + interface OAuth2KnownFields { + id: string + name: string + username: string + avatarURL: string + } + interface OAuth2Config { + providers: Array + mappedFields: OAuth2KnownFields + enabled: boolean + } + interface OAuth2Config { + /** + * GetProviderConfig returns the first OAuth2ProviderConfig that matches the specified name. + * + * Returns false and zero config if no such provider is available in c.Providers. + */ + getProviderConfig(name: string): [OAuth2ProviderConfig, boolean] + } + interface OAuth2Config { + /** + * Validate makes OAuth2Config validatable by implementing [validation.Validatable] interface. + */ + validate(): void + } + interface OAuth2ProviderConfig { + /** + * PKCE overwrites the default provider PKCE config option. + * + * This usually shouldn't be needed but some OAuth2 vendors, like the LinkedIn OIDC, + * may require manual adjustment due to returning error if extra parameters are added to the request + * (https://github.com/pocketbase/pocketbase/discussions/3799#discussioncomment-7640312) + */ + pkce?: boolean + name: string + clientId: string + clientSecret: string + authURL: string + tokenURL: string + userInfoURL: string + displayName: string + extra: _TygojaDict + } + interface OAuth2ProviderConfig { + /** + * Validate makes OAuth2ProviderConfig validatable by implementing [validation.Validatable] interface. + */ + validate(): void + } + interface OAuth2ProviderConfig { + /** + * InitProvider returns a new auth.Provider instance loaded with the current OAuth2ProviderConfig options. + */ + initProvider(): auth.Provider } -} - -/** - * Package jwt is a Go implementation of JSON Web Tokens: http://self-issued.info/docs/draft-jones-json-web-token.html - * - * See README.md for more info. - */ -namespace jwt { /** - * MapClaims is a claims type that uses the map[string]interface{} for JSON decoding. - * This is the default claims type if you don't supply one + * collectionBaseOptions defines the options for the "base" type collection. */ - interface MapClaims extends _TygojaDict{} - interface MapClaims { + interface collectionBaseOptions { + } + /** + * collectionViewOptions defines the options for the "view" type collection. + */ + interface collectionViewOptions { + viewQuery: string + } + interface BaseApp { /** - * VerifyAudience Compares the aud claim against cmp. - * If required is false, this method will return true if the value matches or is unset + * CollectionQuery returns a new Collection select query. */ - verifyAudience(cmp: string, req: boolean): boolean + collectionQuery(): (dbx.SelectQuery) } - interface MapClaims { + interface BaseApp { /** - * VerifyExpiresAt compares the exp claim against cmp (cmp <= exp). - * If req is false, it will return true, if exp is unset. + * FindCollections finds all collections by the given type(s). + * + * If collectionTypes is not set, it returns all collections. + * + * Example: + * + * ``` + * app.FindAllCollections() // all collections + * app.FindAllCollections("auth", "view") // only auth and view collections + * ``` */ - verifyExpiresAt(cmp: number, req: boolean): boolean + findAllCollections(...collectionTypes: string[]): Array<(Collection | undefined)> } - interface MapClaims { + interface BaseApp { /** - * VerifyIssuedAt compares the exp claim against cmp (cmp >= iat). - * If req is false, it will return true, if iat is unset. + * ReloadCachedCollections fetches all collections and caches them into the app store. */ - verifyIssuedAt(cmp: number, req: boolean): boolean + reloadCachedCollections(): void } - interface MapClaims { + interface BaseApp { /** - * VerifyNotBefore compares the nbf claim against cmp (cmp >= nbf). - * If req is false, it will return true, if nbf is unset. + * FindCollectionByNameOrId finds a single collection by its name (case insensitive) or id. */ - verifyNotBefore(cmp: number, req: boolean): boolean + findCollectionByNameOrId(nameOrId: string): (Collection) } - interface MapClaims { + interface BaseApp { /** - * VerifyIssuer compares the iss claim against cmp. - * If required is false, this method will return true if the value matches or is unset + * FindCachedCollectionByNameOrId is similar to [BaseApp.FindCollectionByNameOrId] + * but retrieves the Collection from the app cache instead of making a db call. + * + * NB! This method is suitable for read-only Collection operations. + * + * Returns [sql.ErrNoRows] if no Collection is found for consistency + * with the [BaseApp.FindCollectionByNameOrId] method. + * + * If you plan making changes to the returned Collection model, + * use [BaseApp.FindCollectionByNameOrId] instead. + * + * Caveats: + * + * ``` + * - The returned Collection should be used only for read-only operations. + * Avoid directly modifying the returned cached Collection as it will affect + * the global cached value even if you don't persist the changes in the database! + * - If you are updating a Collection in a transaction and then call this method before commit, + * it'll return the cached Collection state and not the one from the uncommitted transaction. + * - The cache is automatically updated on collections db change (create/update/delete). + * To manually reload the cache you can call [BaseApp.ReloadCachedCollections]. + * ``` */ - verifyIssuer(cmp: string, req: boolean): boolean + findCachedCollectionByNameOrId(nameOrId: string): (Collection) } - interface MapClaims { + interface BaseApp { /** - * Valid validates time based claims "exp, iat, nbf". - * There is no accounting for clock skew. - * As well, if any of the above claims are not in the token, it will still - * be considered a valid claim. + * FindCollectionReferences returns information for all relation fields + * referencing the provided collection. + * + * If the provided collection has reference to itself then it will be + * also included in the result. To exclude it, pass the collection id + * as the excludeIds argument. */ - valid(): void + findCollectionReferences(collection: Collection, ...excludeIds: string[]): _TygojaDict + } + interface BaseApp { + /** + * FindCachedCollectionReferences is similar to [BaseApp.FindCollectionReferences] + * but retrieves the Collection from the app cache instead of making a db call. + * + * NB! This method is suitable for read-only Collection operations. + * + * If you plan making changes to the returned Collection model, + * use [BaseApp.FindCollectionReferences] instead. + * + * Caveats: + * + * ``` + * - The returned Collection should be used only for read-only operations. + * Avoid directly modifying the returned cached Collection as it will affect + * the global cached value even if you don't persist the changes in the database! + * - If you are updating a Collection in a transaction and then call this method before commit, + * it'll return the cached Collection state and not the one from the uncommitted transaction. + * - The cache is automatically updated on collections db change (create/update/delete). + * To manually reload the cache you can call [BaseApp.ReloadCachedCollections]. + * ``` + */ + findCachedCollectionReferences(collection: Collection, ...excludeIds: string[]): _TygojaDict + } + interface BaseApp { + /** + * IsCollectionNameUnique checks that there is no existing collection + * with the provided name (case insensitive!). + * + * Note: case insensitive check because the name is used also as + * table name for the records. + */ + isCollectionNameUnique(name: string, ...excludeIds: string[]): boolean + } + interface BaseApp { + /** + * TruncateCollection deletes all records associated with the provided collection. + * + * The truncate operation is executed in a single transaction, + * aka. either everything is deleted or none. + * + * Note that this method will also trigger the records related + * cascade and file delete actions. + */ + truncateCollection(collection: Collection): void + } + interface BaseApp { + /** + * SyncRecordTableSchema compares the two provided collections + * and applies the necessary related record table changes. + * + * If oldCollection is null, then only newCollection is used to create the record table. + * + * This method is automatically invoked as part of a collection create/update/delete operation. + */ + syncRecordTableSchema(newCollection: Collection, oldCollection: Collection): void + } + interface collectionValidator { + } + interface optionsValidator { + [key:string]: any; } -} - -/** - * Package multipart implements MIME multipart parsing, as defined in RFC - * 2046. - * - * The implementation is sufficient for HTTP (RFC 2388) and the multipart - * bodies generated by popular browsers. - * - * # Limits - * - * To protect against malicious inputs, this package sets limits on the size - * of the MIME data it processes. - * - * [Reader.NextPart] and [Reader.NextRawPart] limit the number of headers in a - * part to 10000 and [Reader.ReadForm] limits the total number of headers in all - * FileHeaders to 10000. - * These limits may be adjusted with the GODEBUG=multipartmaxheaders= - * setting. - * - * Reader.ReadForm further limits the number of parts in a form to 1000. - * This limit may be adjusted with the GODEBUG=multipartmaxparts= - * setting. - */ -namespace multipart { /** - * A FileHeader describes a file part of a multipart request. + * DBExporter defines an interface for custom DB data export. + * Usually used as part of [App.Save]. */ - interface FileHeader { - filename: string - header: textproto.MIMEHeader - size: number - } - interface FileHeader { + interface DBExporter { + [key:string]: any; /** - * Open opens and returns the [FileHeader]'s associated File. + * DBExport returns a key-value map with the data to be used when saving the struct in the database. */ - open(): File + dbExport(app: App): _TygojaDict } -} - -/** - * Package http provides HTTP client and server implementations. - * - * [Get], [Head], [Post], and [PostForm] make HTTP (or HTTPS) requests: - * - * ``` - * resp, err := http.Get("http://example.com/") - * ... - * resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf) - * ... - * resp, err := http.PostForm("http://example.com/form", - * url.Values{"key": {"Value"}, "id": {"123"}}) - * ``` - * - * The caller must close the response body when finished with it: - * - * ``` - * resp, err := http.Get("http://example.com/") - * if err != nil { - * // handle error - * } - * defer resp.Body.Close() - * body, err := io.ReadAll(resp.Body) - * // ... - * ``` - * - * # Clients and Transports - * - * For control over HTTP client headers, redirect policy, and other - * settings, create a [Client]: - * - * ``` - * client := &http.Client{ - * CheckRedirect: redirectPolicyFunc, - * } - * - * resp, err := client.Get("http://example.com") - * // ... - * - * req, err := http.NewRequest("GET", "http://example.com", nil) - * // ... - * req.Header.Add("If-None-Match", `W/"wyzzy"`) - * resp, err := client.Do(req) - * // ... - * ``` - * - * For control over proxies, TLS configuration, keep-alives, - * compression, and other settings, create a [Transport]: - * - * ``` - * tr := &http.Transport{ - * MaxIdleConns: 10, - * IdleConnTimeout: 30 * time.Second, - * DisableCompression: true, - * } - * client := &http.Client{Transport: tr} - * resp, err := client.Get("https://example.com") - * ``` - * - * Clients and Transports are safe for concurrent use by multiple - * goroutines and for efficiency should only be created once and re-used. - * - * # Servers - * - * ListenAndServe starts an HTTP server with a given address and handler. - * The handler is usually nil, which means to use [DefaultServeMux]. - * [Handle] and [HandleFunc] add handlers to [DefaultServeMux]: - * - * ``` - * http.Handle("/foo", fooHandler) - * - * http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { - * fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) - * }) - * - * log.Fatal(http.ListenAndServe(":8080", nil)) - * ``` - * - * More control over the server's behavior is available by creating a - * custom Server: - * - * ``` - * s := &http.Server{ - * Addr: ":8080", - * Handler: myHandler, - * ReadTimeout: 10 * time.Second, - * WriteTimeout: 10 * time.Second, - * MaxHeaderBytes: 1 << 20, - * } - * log.Fatal(s.ListenAndServe()) - * ``` - * - * # HTTP/2 - * - * Starting with Go 1.6, the http package has transparent support for the - * HTTP/2 protocol when using HTTPS. Programs that must disable HTTP/2 - * can do so by setting [Transport.TLSNextProto] (for clients) or - * [Server.TLSNextProto] (for servers) to a non-nil, empty - * map. Alternatively, the following GODEBUG settings are - * currently supported: - * - * ``` - * GODEBUG=http2client=0 # disable HTTP/2 client support - * GODEBUG=http2server=0 # disable HTTP/2 server support - * GODEBUG=http2debug=1 # enable verbose HTTP/2 debug logs - * GODEBUG=http2debug=2 # ... even more verbose, with frame dumps - * ``` - * - * Please report any issues before disabling HTTP/2 support: https://golang.org/s/http2bug - * - * The http package's [Transport] and [Server] both automatically enable - * HTTP/2 support for simple configurations. To enable HTTP/2 for more - * complex configurations, to use lower-level HTTP/2 features, or to use - * a newer version of Go's http2 package, import "golang.org/x/net/http2" - * directly and use its ConfigureTransport and/or ConfigureServer - * functions. Manually configuring HTTP/2 via the golang.org/x/net/http2 - * package takes precedence over the net/http package's built-in HTTP/2 - * support. - */ -namespace http { - // @ts-ignore - import mathrand = rand - // @ts-ignore - import urlpkg = url /** - * A Request represents an HTTP request received by a server - * or to be sent by a client. - * - * The field semantics differ slightly between client and server - * usage. In addition to the notes on the fields below, see the - * documentation for [Request.Write] and [RoundTripper]. + * PreValidator defines an optional model interface for registering a + * function that will run BEFORE firing the validation hooks (see [App.ValidateWithContext]). */ - interface Request { + interface PreValidator { + [key:string]: any; /** - * Method specifies the HTTP method (GET, POST, PUT, etc.). - * For client requests, an empty string means GET. + * PreValidate defines a function that runs BEFORE the validation hooks. */ - method: string + preValidate(ctx: context.Context, app: App): void + } + /** + * PostValidator defines an optional model interface for registering a + * function that will run AFTER executing the validation hooks (see [App.ValidateWithContext]). + */ + interface PostValidator { + [key:string]: any; /** - * URL specifies either the URI being requested (for server - * requests) or the URL to access (for client requests). - * - * For server requests, the URL is parsed from the URI - * supplied on the Request-Line as stored in RequestURI. For - * most requests, fields other than Path and RawQuery will be - * empty. (See RFC 7230, Section 5.3) - * - * For client requests, the URL's Host specifies the server to - * connect to, while the Request's Host field optionally - * specifies the Host header value to send in the HTTP - * request. + * PostValidate defines a function that runs AFTER the successful + * execution of the validation hooks. */ - url?: url.URL + postValidate(ctx: context.Context, app: App): void + } + interface generateDefaultRandomId { /** - * The protocol version for incoming server requests. - * - * For client requests, these fields are ignored. The HTTP - * client code always uses either HTTP/1.1 or HTTP/2. - * See the docs on Transport for details. + * GenerateDefaultRandomId generates a default random id string + * (note: the generated random string is not intended for security purposes). */ - proto: string // "HTTP/1.0" - protoMajor: number // 1 - protoMinor: number // 0 + (): string + } + interface BaseApp { /** - * Header contains the request header fields either received - * by the server or to be sent by the client. - * - * If a server received a request with header lines, - * - * ``` - * Host: example.com - * accept-encoding: gzip, deflate - * Accept-Language: en-us - * fOO: Bar - * foo: two - * ``` - * - * then - * - * ``` - * Header = map[string][]string{ - * "Accept-Encoding": {"gzip, deflate"}, - * "Accept-Language": {"en-us"}, - * "Foo": {"Bar", "two"}, - * } - * ``` - * - * For incoming requests, the Host header is promoted to the - * Request.Host field and removed from the Header map. + * ModelQuery creates a new preconfigured select data.db query with preset + * SELECT, FROM and other common fields based on the provided model. + */ + modelQuery(m: Model): (dbx.SelectQuery) + } + interface BaseApp { + /** + * AuxModelQuery creates a new preconfigured select auxiliary.db query with preset + * SELECT, FROM and other common fields based on the provided model. + */ + auxModelQuery(m: Model): (dbx.SelectQuery) + } + interface BaseApp { + /** + * Delete deletes the specified model from the regular app database. + */ + delete(model: Model): void + } + interface BaseApp { + /** + * Delete deletes the specified model from the regular app database + * (the context could be used to limit the query execution). + */ + deleteWithContext(ctx: context.Context, model: Model): void + } + interface BaseApp { + /** + * AuxDelete deletes the specified model from the auxiliary database. + */ + auxDelete(model: Model): void + } + interface BaseApp { + /** + * AuxDeleteWithContext deletes the specified model from the auxiliary database + * (the context could be used to limit the query execution). + */ + auxDeleteWithContext(ctx: context.Context, model: Model): void + } + interface BaseApp { + /** + * Save validates and saves the specified model into the regular app database. * - * HTTP defines that header names are case-insensitive. The - * request parser implements this by using CanonicalHeaderKey, - * making the first character and any characters following a - * hyphen uppercase and the rest lowercase. + * If you don't want to run validations, use [App.SaveNoValidate()]. + */ + save(model: Model): void + } + interface BaseApp { + /** + * SaveWithContext is the same as [App.Save()] but allows specifying a context to limit the db execution. * - * For client requests, certain headers such as Content-Length - * and Connection are automatically written when needed and - * values in Header may be ignored. See the documentation - * for the Request.Write method. + * If you don't want to run validations, use [App.SaveNoValidateWithContext()]. */ - header: Header + saveWithContext(ctx: context.Context, model: Model): void + } + interface BaseApp { /** - * Body is the request's body. + * SaveNoValidate saves the specified model into the regular app database without performing validations. * - * For client requests, a nil body means the request has no - * body, such as a GET request. The HTTP Client's Transport - * is responsible for calling the Close method. + * If you want to also run validations before persisting, use [App.Save()]. + */ + saveNoValidate(model: Model): void + } + interface BaseApp { + /** + * SaveNoValidateWithContext is the same as [App.SaveNoValidate()] + * but allows specifying a context to limit the db execution. * - * For server requests, the Request Body is always non-nil - * but will return EOF immediately when no body is present. - * The Server will close the request body. The ServeHTTP - * Handler does not need to. + * If you want to also run validations before persisting, use [App.SaveWithContext()]. + */ + saveNoValidateWithContext(ctx: context.Context, model: Model): void + } + interface BaseApp { + /** + * AuxSave validates and saves the specified model into the auxiliary app database. * - * Body must allow Read to be called concurrently with Close. - * In particular, calling Close should unblock a Read waiting - * for input. + * If you don't want to run validations, use [App.AuxSaveNoValidate()]. */ - body: io.ReadCloser + auxSave(model: Model): void + } + interface BaseApp { /** - * GetBody defines an optional func to return a new copy of - * Body. It is used for client requests when a redirect requires - * reading the body more than once. Use of GetBody still - * requires setting Body. + * AuxSaveWithContext is the same as [App.AuxSave()] but allows specifying a context to limit the db execution. * - * For server requests, it is unused. + * If you don't want to run validations, use [App.AuxSaveNoValidateWithContext()]. */ - getBody: () => io.ReadCloser + auxSaveWithContext(ctx: context.Context, model: Model): void + } + interface BaseApp { /** - * ContentLength records the length of the associated content. - * The value -1 indicates that the length is unknown. - * Values >= 0 indicate that the given number of bytes may - * be read from Body. + * AuxSaveNoValidate saves the specified model into the auxiliary app database without performing validations. * - * For client requests, a value of 0 with a non-nil Body is - * also treated as unknown. + * If you want to also run validations before persisting, use [App.AuxSave()]. */ - contentLength: number + auxSaveNoValidate(model: Model): void + } + interface BaseApp { /** - * TransferEncoding lists the transfer encodings from outermost to - * innermost. An empty list denotes the "identity" encoding. - * TransferEncoding can usually be ignored; chunked encoding is - * automatically added and removed as necessary when sending and - * receiving requests. + * AuxSaveNoValidateWithContext is the same as [App.AuxSaveNoValidate()] + * but allows specifying a context to limit the db execution. + * + * If you want to also run validations before persisting, use [App.AuxSaveWithContext()]. */ - transferEncoding: Array + auxSaveNoValidateWithContext(ctx: context.Context, model: Model): void + } + interface BaseApp { /** - * Close indicates whether to close the connection after - * replying to this request (for servers) or after sending this - * request and reading its response (for clients). - * - * For server requests, the HTTP server handles this automatically - * and this field is not needed by Handlers. - * - * For client requests, setting this field prevents re-use of - * TCP connections between requests to the same hosts, as if - * Transport.DisableKeepAlives were set. + * Validate triggers the OnModelValidate hook for the specified model. */ - close: boolean + validate(model: Model): void + } + interface BaseApp { /** - * For server requests, Host specifies the host on which the - * URL is sought. For HTTP/1 (per RFC 7230, section 5.4), this - * is either the value of the "Host" header or the host name - * given in the URL itself. For HTTP/2, it is the value of the - * ":authority" pseudo-header field. - * It may be of the form "host:port". For international domain - * names, Host may be in Punycode or Unicode form. Use - * golang.org/x/net/idna to convert it to either format if - * needed. - * To prevent DNS rebinding attacks, server Handlers should - * validate that the Host header has a value for which the - * Handler considers itself authoritative. The included - * ServeMux supports patterns registered to particular host - * names and thus protects its registered Handlers. - * - * For client requests, Host optionally overrides the Host - * header to send. If empty, the Request.Write method uses - * the value of URL.Host. Host may contain an international - * domain name. + * ValidateWithContext is the same as Validate but allows specifying the ModelEvent context. */ - host: string + validateWithContext(ctx: context.Context, model: Model): void + } + /** + * note: expects both builder to use the same driver + */ + interface dualDBBuilder { + } + interface dualDBBuilder { /** - * Form contains the parsed form data, including both the URL - * field's query parameters and the PATCH, POST, or PUT form data. - * This field is only available after ParseForm is called. - * The HTTP client ignores Form and uses Body instead. + * Select implements the [dbx.Builder.Select] interface method. */ - form: url.Values + select(...cols: string[]): (dbx.SelectQuery) + } + interface dualDBBuilder { /** - * PostForm contains the parsed form data from PATCH, POST - * or PUT body parameters. - * - * This field is only available after ParseForm is called. - * The HTTP client ignores PostForm and uses Body instead. + * Model implements the [dbx.Builder.Model] interface method. */ - postForm: url.Values + model(data: { + }): (dbx.ModelQuery) + } + interface dualDBBuilder { /** - * MultipartForm is the parsed multipart form, including file uploads. - * This field is only available after ParseMultipartForm is called. - * The HTTP client ignores MultipartForm and uses Body instead. + * GeneratePlaceholder implements the [dbx.Builder.GeneratePlaceholder] interface method. */ - multipartForm?: multipart.Form + generatePlaceholder(i: number): string + } + interface dualDBBuilder { /** - * Trailer specifies additional headers that are sent after the request - * body. - * - * For server requests, the Trailer map initially contains only the - * trailer keys, with nil values. (The client declares which trailers it - * will later send.) While the handler is reading from Body, it must - * not reference Trailer. After reading from Body returns EOF, Trailer - * can be read again and will contain non-nil values, if they were sent - * by the client. - * - * For client requests, Trailer must be initialized to a map containing - * the trailer keys to later send. The values may be nil or their final - * values. The ContentLength must be 0 or -1, to send a chunked request. - * After the HTTP request is sent the map values can be updated while - * the request body is read. Once the body returns EOF, the caller must - * not mutate Trailer. - * - * Few HTTP clients, servers, or proxies support HTTP trailers. + * Quote implements the [dbx.Builder.Quote] interface method. */ - trailer: Header + quote(str: string): string + } + interface dualDBBuilder { /** - * RemoteAddr allows HTTP servers and other software to record - * the network address that sent the request, usually for - * logging. This field is not filled in by ReadRequest and - * has no defined format. The HTTP server in this package - * sets RemoteAddr to an "IP:port" address before invoking a - * handler. - * This field is ignored by the HTTP client. + * QuoteSimpleTableName implements the [dbx.Builder.QuoteSimpleTableName] interface method. */ - remoteAddr: string + quoteSimpleTableName(table: string): string + } + interface dualDBBuilder { /** - * RequestURI is the unmodified request-target of the - * Request-Line (RFC 7230, Section 3.1.1) as sent by the client - * to a server. Usually the URL field should be used instead. - * It is an error to set this field in an HTTP client request. + * QuoteSimpleColumnName implements the [dbx.Builder.QuoteSimpleColumnName] interface method. */ - requestURI: string + quoteSimpleColumnName(col: string): string + } + interface dualDBBuilder { /** - * TLS allows HTTP servers and other software to record - * information about the TLS connection on which the request - * was received. This field is not filled in by ReadRequest. - * The HTTP server in this package sets the field for - * TLS-enabled connections before invoking a handler; - * otherwise it leaves the field nil. - * This field is ignored by the HTTP client. + * QueryBuilder implements the [dbx.Builder.QueryBuilder] interface method. */ - tls?: any + queryBuilder(): dbx.QueryBuilder + } + interface dualDBBuilder { /** - * Cancel is an optional channel whose closure indicates that the client - * request should be regarded as canceled. Not all implementations of - * RoundTripper may support Cancel. - * - * For server requests, this field is not applicable. - * - * Deprecated: Set the Request's context with NewRequestWithContext - * instead. If a Request's Cancel field and context are both - * set, it is undefined whether Cancel is respected. + * Insert implements the [dbx.Builder.Insert] interface method. */ - cancel: undefined + insert(table: string, cols: dbx.Params): (dbx.Query) + } + interface dualDBBuilder { /** - * Response is the redirect response which caused this request - * to be created. This field is only populated during client - * redirects. + * Upsert implements the [dbx.Builder.Upsert] interface method. */ - response?: Response + upsert(table: string, cols: dbx.Params, ...constraints: string[]): (dbx.Query) + } + interface dualDBBuilder { /** - * Pattern is the [ServeMux] pattern that matched the request. - * It is empty if the request was not matched against a pattern. + * Update implements the [dbx.Builder.Update] interface method. */ - pattern: string + update(table: string, cols: dbx.Params, where: dbx.Expression): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * Context returns the request's context. To change the context, use - * [Request.Clone] or [Request.WithContext]. - * - * The returned context is always non-nil; it defaults to the - * background context. - * - * For outgoing client requests, the context controls cancellation. - * - * For incoming server requests, the context is canceled when the - * client's connection closes, the request is canceled (with HTTP/2), - * or when the ServeHTTP method returns. + * Delete implements the [dbx.Builder.Delete] interface method. */ - context(): context.Context + delete(table: string, where: dbx.Expression): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * WithContext returns a shallow copy of r with its context changed - * to ctx. The provided ctx must be non-nil. - * - * For outgoing client request, the context controls the entire - * lifetime of a request and its response: obtaining a connection, - * sending the request, and reading the response headers and body. - * - * To create a new request with a context, use [NewRequestWithContext]. - * To make a deep copy of a request with a new context, use [Request.Clone]. + * CreateTable implements the [dbx.Builder.CreateTable] interface method. */ - withContext(ctx: context.Context): (Request) + createTable(table: string, cols: _TygojaDict, ...options: string[]): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * Clone returns a deep copy of r with its context changed to ctx. - * The provided ctx must be non-nil. - * - * Clone only makes a shallow copy of the Body field. - * - * For an outgoing client request, the context controls the entire - * lifetime of a request and its response: obtaining a connection, - * sending the request, and reading the response headers and body. + * RenameTable implements the [dbx.Builder.RenameTable] interface method. */ - clone(ctx: context.Context): (Request) + renameTable(oldName: string, newName: string): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * ProtoAtLeast reports whether the HTTP protocol used - * in the request is at least major.minor. + * DropTable implements the [dbx.Builder.DropTable] interface method. */ - protoAtLeast(major: number, minor: number): boolean + dropTable(table: string): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * UserAgent returns the client's User-Agent, if sent in the request. + * TruncateTable implements the [dbx.Builder.TruncateTable] interface method. */ - userAgent(): string + truncateTable(table: string): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * Cookies parses and returns the HTTP cookies sent with the request. + * AddColumn implements the [dbx.Builder.AddColumn] interface method. */ - cookies(): Array<(Cookie | undefined)> + addColumn(table: string, col: string, typ: string): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * CookiesNamed parses and returns the named HTTP cookies sent with the request - * or an empty slice if none matched. + * DropColumn implements the [dbx.Builder.DropColumn] interface method. */ - cookiesNamed(name: string): Array<(Cookie | undefined)> + dropColumn(table: string, col: string): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * Cookie returns the named cookie provided in the request or - * [ErrNoCookie] if not found. - * If multiple cookies match the given name, only one cookie will - * be returned. + * RenameColumn implements the [dbx.Builder.RenameColumn] interface method. */ - cookie(name: string): (Cookie) + renameColumn(table: string, oldName: string, newName: string): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * AddCookie adds a cookie to the request. Per RFC 6265 section 5.4, - * AddCookie does not attach more than one [Cookie] header field. That - * means all cookies, if any, are written into the same line, - * separated by semicolon. - * AddCookie only sanitizes c's name and value, and does not sanitize - * a Cookie header already present in the request. + * AlterColumn implements the [dbx.Builder.AlterColumn] interface method. */ - addCookie(c: Cookie): void + alterColumn(table: string, col: string, typ: string): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * Referer returns the referring URL, if sent in the request. - * - * Referer is misspelled as in the request itself, a mistake from the - * earliest days of HTTP. This value can also be fetched from the - * [Header] map as Header["Referer"]; the benefit of making it available - * as a method is that the compiler can diagnose programs that use the - * alternate (correct English) spelling req.Referrer() but cannot - * diagnose programs that use Header["Referrer"]. + * AddPrimaryKey implements the [dbx.Builder.AddPrimaryKey] interface method. */ - referer(): string + addPrimaryKey(table: string, name: string, ...cols: string[]): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * MultipartReader returns a MIME multipart reader if this is a - * multipart/form-data or a multipart/mixed POST request, else returns nil and an error. - * Use this function instead of [Request.ParseMultipartForm] to - * process the request body as a stream. + * DropPrimaryKey implements the [dbx.Builder.DropPrimaryKey] interface method. */ - multipartReader(): (multipart.Reader) + dropPrimaryKey(table: string, name: string): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * Write writes an HTTP/1.1 request, which is the header and body, in wire format. - * This method consults the following fields of the request: - * - * ``` - * Host - * URL - * Method (defaults to "GET") - * Header - * ContentLength - * TransferEncoding - * Body - * ``` - * - * If Body is present, Content-Length is <= 0 and [Request.TransferEncoding] - * hasn't been set to "identity", Write adds "Transfer-Encoding: - * chunked" to the header. Body is closed after it is sent. + * AddForeignKey implements the [dbx.Builder.AddForeignKey] interface method. */ - write(w: io.Writer): void + addForeignKey(table: string, name: string, cols: Array, refCols: Array, refTable: string, ...options: string[]): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * WriteProxy is like [Request.Write] but writes the request in the form - * expected by an HTTP proxy. In particular, [Request.WriteProxy] writes the - * initial Request-URI line of the request with an absolute URI, per - * section 5.3 of RFC 7230, including the scheme and host. - * In either case, WriteProxy also writes a Host header, using - * either r.Host or r.URL.Host. + * DropForeignKey implements the [dbx.Builder.DropForeignKey] interface method. */ - writeProxy(w: io.Writer): void + dropForeignKey(table: string, name: string): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * BasicAuth returns the username and password provided in the request's - * Authorization header, if the request uses HTTP Basic Authentication. - * See RFC 2617, Section 2. + * CreateIndex implements the [dbx.Builder.CreateIndex] interface method. */ - basicAuth(): [string, string, boolean] + createIndex(table: string, name: string, ...cols: string[]): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * SetBasicAuth sets the request's Authorization header to use HTTP - * Basic Authentication with the provided username and password. - * - * With HTTP Basic Authentication the provided username and password - * are not encrypted. It should generally only be used in an HTTPS - * request. - * - * The username may not contain a colon. Some protocols may impose - * additional requirements on pre-escaping the username and - * password. For instance, when used with OAuth2, both arguments must - * be URL encoded first with [url.QueryEscape]. + * CreateUniqueIndex implements the [dbx.Builder.CreateUniqueIndex] interface method. */ - setBasicAuth(username: string, password: string): void + createUniqueIndex(table: string, name: string, ...cols: string[]): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * ParseForm populates r.Form and r.PostForm. - * - * For all requests, ParseForm parses the raw query from the URL and updates - * r.Form. - * - * For POST, PUT, and PATCH requests, it also reads the request body, parses it - * as a form and puts the results into both r.PostForm and r.Form. Request body - * parameters take precedence over URL query string values in r.Form. - * - * If the request Body's size has not already been limited by [MaxBytesReader], - * the size is capped at 10MB. - * - * For other HTTP methods, or when the Content-Type is not - * application/x-www-form-urlencoded, the request Body is not read, and - * r.PostForm is initialized to a non-nil, empty value. - * - * [Request.ParseMultipartForm] calls ParseForm automatically. - * ParseForm is idempotent. + * DropIndex implements the [dbx.Builder.DropIndex] interface method. */ - parseForm(): void + dropIndex(table: string, name: string): (dbx.Query) } - interface Request { + interface dualDBBuilder { /** - * ParseMultipartForm parses a request body as multipart/form-data. - * The whole request body is parsed and up to a total of maxMemory bytes of - * its file parts are stored in memory, with the remainder stored on - * disk in temporary files. - * ParseMultipartForm calls [Request.ParseForm] if necessary. - * If ParseForm returns an error, ParseMultipartForm returns it but also - * continues parsing the request body. - * After one call to ParseMultipartForm, subsequent calls have no effect. + * NewQuery implements the [dbx.Builder.NewQuery] interface method by + * routing the SELECT queries to the concurrent builder instance. */ - parseMultipartForm(maxMemory: number): void + newQuery(str: string): (dbx.Query) } - interface Request { + interface defaultDBConnect { + (dbPath: string): (dbx.DB) + } + /** + * Model defines an interface with common methods that all db models should have. + * + * Note: for simplicity composite pk are not supported. + */ + interface Model { + [key:string]: any; + tableName(): string + pk(): any + lastSavedPK(): any + isNew(): boolean + markAsNew(): void + markAsNotNew(): void + } + /** + * BaseModel defines a base struct that is intended to be embedded into other custom models. + */ + interface BaseModel { /** - * FormValue returns the first value for the named component of the query. - * The precedence order: - * 1. application/x-www-form-urlencoded form body (POST, PUT, PATCH only) - * 2. query parameters (always) - * 3. multipart/form-data form body (always) - * - * FormValue calls [Request.ParseMultipartForm] and [Request.ParseForm] - * if necessary and ignores any errors returned by these functions. - * If key is not present, FormValue returns the empty string. - * To access multiple values of the same key, call ParseForm and - * then inspect [Request.Form] directly. + * Id is the primary key of the model. + * It is usually autogenerated by the parent model implementation. */ - formValue(key: string): string + id: string } - interface Request { + interface BaseModel { /** - * PostFormValue returns the first value for the named component of the POST, - * PUT, or PATCH request body. URL query parameters are ignored. - * PostFormValue calls [Request.ParseMultipartForm] and [Request.ParseForm] if necessary and ignores - * any errors returned by these functions. - * If key is not present, PostFormValue returns the empty string. + * LastSavedPK returns the last saved primary key of the model. + * + * Its value is updated to the latest PK value after MarkAsNotNew() or PostScan() calls. */ - postFormValue(key: string): string + lastSavedPK(): any } - interface Request { + interface BaseModel { + pk(): any + } + interface BaseModel { /** - * FormFile returns the first file for the provided form key. - * FormFile calls [Request.ParseMultipartForm] and [Request.ParseForm] if necessary. + * IsNew indicates what type of db query (insert or update) + * should be used with the model instance. */ - formFile(key: string): [multipart.File, (multipart.FileHeader)] + isNew(): boolean } - interface Request { + interface BaseModel { /** - * PathValue returns the value for the named path wildcard in the [ServeMux] pattern - * that matched the request. - * It returns the empty string if the request was not matched against a pattern - * or there is no such wildcard in the pattern. + * MarkAsNew clears the pk field and marks the current model as "new" + * (aka. forces m.IsNew() to be true). */ - pathValue(name: string): string + markAsNew(): void } - interface Request { + interface BaseModel { /** - * SetPathValue sets name to value, so that subsequent calls to r.PathValue(name) - * return value. + * MarkAsNew set the pk field to the Id value and marks the current model + * as NOT "new" (aka. forces m.IsNew() to be false). */ - setPathValue(name: string, value: string): void + markAsNotNew(): void } - /** - * A ResponseWriter interface is used by an HTTP handler to - * construct an HTTP response. - * - * A ResponseWriter may not be used after [Handler.ServeHTTP] has returned. - */ - interface ResponseWriter { - [key:string]: any; + interface BaseModel { /** - * Header returns the header map that will be sent by - * [ResponseWriter.WriteHeader]. The [Header] map also is the mechanism with which - * [Handler] implementations can set HTTP trailers. - * - * Changing the header map after a call to [ResponseWriter.WriteHeader] (or - * [ResponseWriter.Write]) has no effect unless the HTTP status code was of the - * 1xx class or the modified headers are trailers. - * - * There are two ways to set Trailers. The preferred way is to - * predeclare in the headers which trailers you will later - * send by setting the "Trailer" header to the names of the - * trailer keys which will come later. In this case, those - * keys of the Header map are treated as if they were - * trailers. See the example. The second way, for trailer - * keys not known to the [Handler] until after the first [ResponseWriter.Write], - * is to prefix the [Header] map keys with the [TrailerPrefix] - * constant value. + * PostScan implements the [dbx.PostScanner] interface. * - * To suppress automatic response headers (such as "Date"), set - * their value to nil. + * It is usually executed right after the model is populated with the db row values. */ - header(): Header + postScan(): void + } + interface BaseApp { /** - * Write writes the data to the connection as part of an HTTP reply. - * - * If [ResponseWriter.WriteHeader] has not yet been called, Write calls - * WriteHeader(http.StatusOK) before writing the data. If the Header - * does not contain a Content-Type line, Write adds a Content-Type set - * to the result of passing the initial 512 bytes of written data to - * [DetectContentType]. Additionally, if the total size of all written - * data is under a few KB and there are no Flush calls, the - * Content-Length header is added automatically. - * - * Depending on the HTTP protocol version and the client, calling - * Write or WriteHeader may prevent future reads on the - * Request.Body. For HTTP/1.x requests, handlers should read any - * needed request body data before writing the response. Once the - * headers have been flushed (due to either an explicit Flusher.Flush - * call or writing enough data to trigger a flush), the request body - * may be unavailable. For HTTP/2 requests, the Go HTTP server permits - * handlers to continue to read the request body while concurrently - * writing the response. However, such behavior may not be supported - * by all HTTP/2 clients. Handlers should read before writing if - * possible to maximize compatibility. + * TableColumns returns all column names of a single table by its name. */ - write(_arg0: string|Array): number + tableColumns(tableName: string): Array + } + interface TableInfoRow { /** - * WriteHeader sends an HTTP response header with the provided - * status code. + * the `db:"pk"` tag has special semantic so we cannot rename + * the original field without specifying a custom mapper + */ + pk: number + index: number + name: string + type: string + notNull: boolean + defaultValue: sql.NullString + } + interface BaseApp { + /** + * TableInfo returns the "table_info" pragma result for the specified table. + */ + tableInfo(tableName: string): Array<(TableInfoRow | undefined)> + } + interface BaseApp { + /** + * TableIndexes returns a name grouped map with all non empty index of the specified table. * - * If WriteHeader is not called explicitly, the first call to Write - * will trigger an implicit WriteHeader(http.StatusOK). - * Thus explicit calls to WriteHeader are mainly used to - * send error codes or 1xx informational responses. + * Note: This method doesn't return an error on nonexisting table. + */ + tableIndexes(tableName: string): _TygojaDict + } + interface BaseApp { + /** + * DeleteTable drops the specified table. * - * The provided code must be a valid HTTP 1xx-5xx status code. - * Any number of 1xx headers may be written, followed by at most - * one 2xx-5xx header. 1xx headers are sent immediately, but 2xx-5xx - * headers may be buffered. Use the Flusher interface to send - * buffered data. The header map is cleared when 2xx-5xx headers are - * sent, but not with 1xx headers. + * This method is a no-op if a table with the provided name doesn't exist. * - * The server will automatically send a 100 (Continue) header - * on the first read from the request body if the request has - * an "Expect: 100-continue" header. + * NB! Be aware that this method is vulnerable to SQL injection and the + * "tableName" argument must come only from trusted input! */ - writeHeader(statusCode: number): void + deleteTable(tableName: string): void } - /** - * A Server defines parameters for running an HTTP server. - * The zero value for Server is a valid configuration. - */ - interface Server { + interface BaseApp { /** - * Addr optionally specifies the TCP address for the server to listen on, - * in the form "host:port". If empty, ":http" (port 80) is used. - * The service names are defined in RFC 6335 and assigned by IANA. - * See net.Dial for details of the address format. + * HasTable checks if a table (or view) with the provided name exists (case insensitive). + * in the data.db. */ - addr: string - handler: Handler // handler to invoke, http.DefaultServeMux if nil + hasTable(tableName: string): boolean + } + interface BaseApp { /** - * DisableGeneralOptionsHandler, if true, passes "OPTIONS *" requests to the Handler, - * otherwise responds with 200 OK and Content-Length: 0. + * AuxHasTable checks if a table (or view) with the provided name exists (case insensitive) + * in the auixiliary.db. */ - disableGeneralOptionsHandler: boolean + auxHasTable(tableName: string): boolean + } + interface BaseApp { /** - * TLSConfig optionally provides a TLS configuration for use - * by ServeTLS and ListenAndServeTLS. Note that this value is - * cloned by ServeTLS and ListenAndServeTLS, so it's not - * possible to modify the configuration with methods like - * tls.Config.SetSessionTicketKeys. To use - * SetSessionTicketKeys, use Server.Serve with a TLS Listener - * instead. + * Vacuum executes VACUUM on the data.db in order to reclaim unused data db disk space. */ - tlsConfig?: any + vacuum(): void + } + interface BaseApp { /** - * ReadTimeout is the maximum duration for reading the entire - * request, including the body. A zero or negative value means - * there will be no timeout. + * AuxVacuum executes VACUUM on the auxiliary.db in order to reclaim unused auxiliary db disk space. + */ + auxVacuum(): void + } + interface BaseApp { + /** + * RunInTransaction wraps fn into a transaction for the regular app database. * - * Because ReadTimeout does not let Handlers make per-request - * decisions on each request body's acceptable deadline or - * upload rate, most users will prefer to use - * ReadHeaderTimeout. It is valid to use them both. + * It is safe to nest RunInTransaction calls as long as you use the callback's txApp. */ - readTimeout: time.Duration + runInTransaction(fn: (txApp: App) => void): void + } + interface BaseApp { /** - * ReadHeaderTimeout is the amount of time allowed to read - * request headers. The connection's read deadline is reset - * after reading the headers and the Handler can decide what - * is considered too slow for the body. If zero, the value of - * ReadTimeout is used. If negative, or if zero and ReadTimeout - * is zero or negative, there is no timeout. + * AuxRunInTransaction wraps fn into a transaction for the auxiliary app database. + * + * It is safe to nest RunInTransaction calls as long as you use the callback's txApp. */ - readHeaderTimeout: time.Duration + auxRunInTransaction(fn: (txApp: App) => void): void + } + /** + * TxAppInfo represents an active transaction context associated to an existing app instance. + */ + interface TxAppInfo { + } + interface TxAppInfo { /** - * WriteTimeout is the maximum duration before timing out - * writes of the response. It is reset whenever a new - * request's header is read. Like ReadTimeout, it does not - * let Handlers make decisions on a per-request basis. - * A zero or negative value means there will be no timeout. + * OnComplete registers the provided callback that will be invoked + * once the related transaction ends (either completes successfully or rollbacked with an error). + * + * The callback receives the transaction error (if any) as its argument. + * Any additional errors returned by the OnComplete callbacks will be + * joined together with txErr when returning the final transaction result. */ - writeTimeout: time.Duration + onComplete(fn: (txErr: Error) => void): void + } + /** + * RequestEvent defines the PocketBase router handler event. + */ + type _sZbWOhD = router.Event + interface RequestEvent extends _sZbWOhD { + app: App + auth?: Record + } + interface RequestEvent { /** - * IdleTimeout is the maximum amount of time to wait for the - * next request when keep-alives are enabled. If zero, the value - * of ReadTimeout is used. If negative, or if zero and ReadTimeout - * is zero or negative, there is no timeout. + * RealIP returns the "real" IP address from the configured trusted proxy headers. + * + * If Settings.TrustedProxy is not configured or the found IP is empty, + * it fallbacks to e.RemoteIP(). + * + * NB! + * Be careful when used in a security critical context as it relies on + * the trusted proxy to be properly configured and your app to be accessible only through it. + * If you are not sure, use e.RemoteIP(). */ - idleTimeout: time.Duration + realIP(): string + } + interface RequestEvent { /** - * MaxHeaderBytes controls the maximum number of bytes the - * server will read parsing the request header's keys and - * values, including the request line. It does not limit the - * size of the request body. - * If zero, DefaultMaxHeaderBytes is used. - */ - maxHeaderBytes: number - /** - * TLSNextProto optionally specifies a function to take over - * ownership of the provided TLS connection when an ALPN - * protocol upgrade has occurred. The map key is the protocol - * name negotiated. The Handler argument should be used to - * handle HTTP requests and will initialize the Request's TLS - * and RemoteAddr if not already set. The connection is - * automatically closed when the function returns. - * If TLSNextProto is not nil, HTTP/2 support is not enabled - * automatically. + * HasSuperuserAuth checks whether the current RequestEvent has superuser authentication loaded. */ - tlsNextProto: _TygojaDict + hasSuperuserAuth(): boolean + } + interface RequestEvent { /** - * ConnState specifies an optional callback function that is - * called when a client connection changes state. See the - * ConnState type and associated constants for details. + * RequestInfo parses the current request into RequestInfo instance. + * + * Note that the returned result is cached to avoid copying the request data multiple times + * but the auth state and other common store items are always refreshed in case they were changed by another handler. */ - connState: (_arg0: net.Conn, _arg1: ConnState) => void + requestInfo(): (RequestInfo) + } + /** + * RequestInfo defines a HTTP request data struct, usually used + * as part of the `@request.*` filter resolver. + * + * The Query and Headers fields contains only the first value for each found entry. + */ + interface RequestInfo { + query: _TygojaDict + headers: _TygojaDict + body: _TygojaDict + auth?: Record + method: string + context: string + } + interface RequestInfo { /** - * ErrorLog specifies an optional logger for errors accepting - * connections, unexpected behavior from handlers, and - * underlying FileSystem errors. - * If nil, logging is done via the log package's standard logger. + * HasSuperuserAuth checks whether the current RequestInfo instance + * has superuser authentication loaded. */ - errorLog?: any + hasSuperuserAuth(): boolean + } + interface RequestInfo { /** - * BaseContext optionally specifies a function that returns - * the base context for incoming requests on this server. - * The provided Listener is the specific Listener that's - * about to start accepting requests. - * If BaseContext is nil, the default is context.Background(). - * If non-nil, it must return a non-nil context. + * Clone creates a new shallow copy of the current RequestInfo and its Auth record (if any). */ - baseContext: (_arg0: net.Listener) => context.Context + clone(): (RequestInfo) + } + type _sBVknZE = hook.Event&RequestEvent + interface BatchRequestEvent extends _sBVknZE { + batch: Array<(InternalRequest | undefined)> + } + interface InternalRequest { /** - * ConnContext optionally specifies a function that modifies - * the context used for a new connection c. The provided ctx - * is derived from the base context and has a ServerContextKey - * value. + * note: for uploading files the value must be either *filesystem.File or []*filesystem.File */ - connContext: (ctx: context.Context, c: net.Conn) => context.Context + body: _TygojaDict + headers: _TygojaDict + method: string + url: string } - interface Server { + interface InternalRequest { + validate(): void + } + interface HookTagger { + [key:string]: any; + hookTags(): Array + } + interface baseModelEventData { + model: Model + } + interface baseModelEventData { + tags(): Array + } + interface baseRecordEventData { + record?: Record + } + interface baseRecordEventData { + tags(): Array + } + interface baseCollectionEventData { + collection?: Collection + } + interface baseCollectionEventData { + tags(): Array + } + type _sSbngvG = hook.Event + interface BootstrapEvent extends _sSbngvG { + app: App + } + type _sHXwxyi = hook.Event + interface TerminateEvent extends _sHXwxyi { + app: App + isRestart: boolean + } + type _sAGsfdD = hook.Event + interface BackupEvent extends _sAGsfdD { + app: App + context: context.Context + name: string // the name of the backup to create/restore. + exclude: Array // list of dir entries to exclude from the backup create/restore. + } + type _shFhRPx = hook.Event + interface ServeEvent extends _shFhRPx { + app: App + router?: router.Router + server?: http.Server + certManager?: any /** - * Close immediately closes all active net.Listeners and any - * connections in state [StateNew], [StateActive], or [StateIdle]. For a - * graceful shutdown, use [Server.Shutdown]. - * - * Close does not attempt to close (and does not even know about) - * any hijacked connections, such as WebSockets. + * Listener allow specifying a custom network listener. * - * Close returns any error returned from closing the [Server]'s - * underlying Listener(s). + * Leave it nil to use the default net.Listen("tcp", e.Server.Addr). */ - close(): void - } - interface Server { + listener: net.Listener /** - * Shutdown gracefully shuts down the server without interrupting any - * active connections. Shutdown works by first closing all open - * listeners, then closing all idle connections, and then waiting - * indefinitely for connections to return to idle and then shut down. - * If the provided context expires before the shutdown is complete, - * Shutdown returns the context's error, otherwise it returns any - * error returned from closing the [Server]'s underlying Listener(s). + * InstallerFunc is the "installer" function that is called after + * successful server tcp bind but only if there is no explicit + * superuser record created yet. * - * When Shutdown is called, [Serve], [ListenAndServe], and - * [ListenAndServeTLS] immediately return [ErrServerClosed]. Make sure the - * program doesn't exit and waits instead for Shutdown to return. + * It runs in a separate goroutine and its default value is [apis.DefaultInstallerFunc]. * - * Shutdown does not attempt to close nor wait for hijacked - * connections such as WebSockets. The caller of Shutdown should - * separately notify such long-lived connections of shutdown and wait - * for them to close, if desired. See [Server.RegisterOnShutdown] for a way to - * register shutdown notification functions. + * It receives a system superuser record as argument that you can use to generate + * a short-lived auth token (e.g. systemSuperuser.NewStaticAuthToken(30 * time.Minute)) + * and concatenate it as query param for your installer page + * (if you are using the client-side SDKs, you can then load the + * token with pb.authStore.save(token) and perform any Web API request + * e.g. creating a new superuser). * - * Once Shutdown has been called on a server, it may not be reused; - * future calls to methods such as Serve will return ErrServerClosed. + * Set it to nil if you want to skip the installer. */ - shutdown(ctx: context.Context): void + installerFunc: (app: App, systemSuperuser: Record, baseURL: string) => void } - interface Server { + type _smcGTjR = hook.Event&RequestEvent + interface SettingsListRequestEvent extends _smcGTjR { + settings?: Settings + } + type _sOCaERj = hook.Event&RequestEvent + interface SettingsUpdateRequestEvent extends _sOCaERj { + oldSettings?: Settings + newSettings?: Settings + } + type _sCmRree = hook.Event + interface SettingsReloadEvent extends _sCmRree { + app: App + } + type _stUYeSJ = hook.Event + interface MailerEvent extends _stUYeSJ { + app: App + mailer: mailer.Mailer + message?: mailer.Message + } + type _sCDPvvu = MailerEvent&baseRecordEventData + interface MailerRecordEvent extends _sCDPvvu { + meta: _TygojaDict + } + type _shFhsxv = hook.Event&baseModelEventData + interface ModelEvent extends _shFhsxv { + app: App + context: context.Context /** - * RegisterOnShutdown registers a function to call on [Server.Shutdown]. - * This can be used to gracefully shutdown connections that have - * undergone ALPN protocol upgrade or that have been hijacked. - * This function should start protocol-specific graceful shutdown, - * but should not wait for shutdown to complete. + * Could be any of the ModelEventType* constants, like: + * - create + * - update + * - delete + * - validate */ - registerOnShutdown(f: () => void): void + type: string } - interface Server { + type _sLfKOib = ModelEvent + interface ModelErrorEvent extends _sLfKOib { + error: Error + } + type _sNgOXKJ = hook.Event&baseRecordEventData + interface RecordEvent extends _sNgOXKJ { + app: App + context: context.Context /** - * ListenAndServe listens on the TCP network address srv.Addr and then - * calls [Serve] to handle requests on incoming connections. - * Accepted connections are configured to enable TCP keep-alives. - * - * If srv.Addr is blank, ":http" is used. - * - * ListenAndServe always returns a non-nil error. After [Server.Shutdown] or [Server.Close], - * the returned error is [ErrServerClosed]. + * Could be any of the ModelEventType* constants, like: + * - create + * - update + * - delete + * - validate */ - listenAndServe(): void + type: string } - interface Server { + type _sTexdRl = RecordEvent + interface RecordErrorEvent extends _sTexdRl { + error: Error + } + type _sawrAEi = hook.Event&baseCollectionEventData + interface CollectionEvent extends _sawrAEi { + app: App + context: context.Context /** - * Serve accepts incoming connections on the Listener l, creating a - * new service goroutine for each. The service goroutines read requests and - * then call srv.Handler to reply to them. - * - * HTTP/2 support is only enabled if the Listener returns [*tls.Conn] - * connections and they were configured with "h2" in the TLS - * Config.NextProtos. - * - * Serve always returns a non-nil error and closes l. - * After [Server.Shutdown] or [Server.Close], the returned error is [ErrServerClosed]. + * Could be any of the ModelEventType* constants, like: + * - create + * - update + * - delete + * - validate */ - serve(l: net.Listener): void + type: string } - interface Server { + type _sXUjqma = CollectionEvent + interface CollectionErrorEvent extends _sXUjqma { + error: Error + } + type _swsOUnh = hook.Event&RequestEvent&baseRecordEventData + interface FileTokenRequestEvent extends _swsOUnh { + token: string + } + type _stWzmAG = hook.Event&RequestEvent&baseCollectionEventData + interface FileDownloadRequestEvent extends _stWzmAG { + record?: Record + fileField?: FileField + servedPath: string + servedName: string /** - * ServeTLS accepts incoming connections on the Listener l, creating a - * new service goroutine for each. The service goroutines perform TLS - * setup and then read requests, calling srv.Handler to reply to them. - * - * Files containing a certificate and matching private key for the - * server must be provided if neither the [Server]'s - * TLSConfig.Certificates, TLSConfig.GetCertificate nor - * config.GetConfigForClient are populated. - * If the certificate is signed by a certificate authority, the - * certFile should be the concatenation of the server's certificate, - * any intermediates, and the CA's certificate. + * ThumbError indicates the a thumb wasn't able to be generated + * (e.g. because it didn't satisfy the support image formats or it timed out). * - * ServeTLS always returns a non-nil error. After [Server.Shutdown] or [Server.Close], the - * returned error is [ErrServerClosed]. + * Note that PocketBase fallbacks to the original file in case of a thumb error, + * but developers can check the field and provide their own custom thumb generation if necessary. */ - serveTLS(l: net.Listener, certFile: string, keyFile: string): void + thumbError: Error } - interface Server { + type _sffjriX = hook.Event&RequestEvent + interface CollectionsListRequestEvent extends _sffjriX { + collections: Array<(Collection | undefined)> + result?: search.Result + } + type _scQdRRd = hook.Event&RequestEvent + interface CollectionsImportRequestEvent extends _scQdRRd { + collectionsData: Array<_TygojaDict> + deleteMissing: boolean + } + type _ssxdGMk = hook.Event&RequestEvent&baseCollectionEventData + interface CollectionRequestEvent extends _ssxdGMk { + } + type _suAsugF = hook.Event&RequestEvent + interface RealtimeConnectRequestEvent extends _suAsugF { + client: subscriptions.Client /** - * SetKeepAlivesEnabled controls whether HTTP keep-alives are enabled. - * By default, keep-alives are always enabled. Only very - * resource-constrained environments or servers in the process of - * shutting down should disable them. + * note: modifying it after the connect has no effect */ - setKeepAlivesEnabled(v: boolean): void + idleTimeout: time.Duration } - interface Server { + type _sMAEAck = hook.Event&RequestEvent + interface RealtimeMessageEvent extends _sMAEAck { + client: subscriptions.Client + message?: subscriptions.Message + } + type _sdcgymb = hook.Event&RequestEvent + interface RealtimeSubscribeRequestEvent extends _sdcgymb { + client: subscriptions.Client + subscriptions: Array + } + type _sosMlfP = hook.Event&RequestEvent&baseCollectionEventData + interface RecordsListRequestEvent extends _sosMlfP { /** - * ListenAndServeTLS listens on the TCP network address srv.Addr and - * then calls [ServeTLS] to handle requests on incoming TLS connections. - * Accepted connections are configured to enable TCP keep-alives. - * - * Filenames containing a certificate and matching private key for the - * server must be provided if neither the [Server]'s TLSConfig.Certificates - * nor TLSConfig.GetCertificate are populated. If the certificate is - * signed by a certificate authority, the certFile should be the - * concatenation of the server's certificate, any intermediates, and - * the CA's certificate. - * - * If srv.Addr is blank, ":https" is used. - * - * ListenAndServeTLS always returns a non-nil error. After [Server.Shutdown] or - * [Server.Close], the returned error is [ErrServerClosed]. + * @todo consider removing and maybe add as generic to the search.Result? */ - listenAndServeTLS(certFile: string, keyFile: string): void + records: Array<(Record | undefined)> + result?: search.Result + } + type _sypXBrr = hook.Event&RequestEvent&baseCollectionEventData + interface RecordRequestEvent extends _sypXBrr { + record?: Record + } + type _sojgUDG = hook.Event&baseRecordEventData + interface RecordEnrichEvent extends _sojgUDG { + app: App + requestInfo?: RequestInfo + } + type _sGrvoou = hook.Event&RequestEvent&baseCollectionEventData + interface RecordCreateOTPRequestEvent extends _sGrvoou { + record?: Record + password: string + } + type _sknNTSc = hook.Event&RequestEvent&baseCollectionEventData + interface RecordAuthWithOTPRequestEvent extends _sknNTSc { + record?: Record + otp?: OTP + } + type _sOfrDGp = hook.Event&RequestEvent&baseCollectionEventData + interface RecordAuthRequestEvent extends _sOfrDGp { + record?: Record + token: string + meta: any + authMethod: string + } + type _sMBaham = hook.Event&RequestEvent&baseCollectionEventData + interface RecordAuthWithPasswordRequestEvent extends _sMBaham { + record?: Record + identity: string + identityField: string + password: string + } + type _sylMvvz = hook.Event&RequestEvent&baseCollectionEventData + interface RecordAuthWithOAuth2RequestEvent extends _sylMvvz { + providerName: string + providerClient: auth.Provider + record?: Record + oAuth2User?: auth.AuthUser + createData: _TygojaDict + isNewRecord: boolean + } + type _sfDvKdQ = hook.Event&RequestEvent&baseCollectionEventData + interface RecordAuthRefreshRequestEvent extends _sfDvKdQ { + record?: Record + } + type _sHYSSFS = hook.Event&RequestEvent&baseCollectionEventData + interface RecordRequestPasswordResetRequestEvent extends _sHYSSFS { + record?: Record + } + type _ssqoGOa = hook.Event&RequestEvent&baseCollectionEventData + interface RecordConfirmPasswordResetRequestEvent extends _ssqoGOa { + record?: Record + } + type _sKQFakh = hook.Event&RequestEvent&baseCollectionEventData + interface RecordRequestVerificationRequestEvent extends _sKQFakh { + record?: Record + } + type _sTCGcqT = hook.Event&RequestEvent&baseCollectionEventData + interface RecordConfirmVerificationRequestEvent extends _sTCGcqT { + record?: Record + } + type _sBUzYRb = hook.Event&RequestEvent&baseCollectionEventData + interface RecordRequestEmailChangeRequestEvent extends _sBUzYRb { + record?: Record + newEmail: string + } + type _sxebbqd = hook.Event&RequestEvent&baseCollectionEventData + interface RecordConfirmEmailChangeRequestEvent extends _sxebbqd { + record?: Record + newEmail: string } -} - -namespace auth { /** - * AuthUser defines a standardized oauth2 user data structure. + * ExternalAuth defines a Record proxy for working with the externalAuths collection. */ - interface AuthUser { - id: string - name: string - username: string - email: string - avatarUrl: string - accessToken: string - refreshToken: string - expiry: types.DateTime - rawUser: _TygojaDict + type _stkwZQT = Record + interface ExternalAuth extends _stkwZQT { } - /** - * Provider defines a common interface for an OAuth2 client. - */ - interface Provider { - [key:string]: any; + interface newExternalAuth { /** - * Context returns the context associated with the provider (if any). + * NewExternalAuth instantiates and returns a new blank *ExternalAuth model. + * + * Example usage: + * + * ``` + * ea := core.NewExternalAuth(app) + * ea.SetRecordRef(user.Id) + * ea.SetCollectionRef(user.Collection().Id) + * ea.SetProvider("google") + * ea.SetProviderId("...") + * app.Save(ea) + * ``` */ - context(): context.Context + (app: App): (ExternalAuth) + } + interface ExternalAuth { /** - * SetContext assigns the specified context to the current provider. + * PreValidate implements the [PreValidator] interface and checks + * whether the proxy is properly loaded. */ - setContext(ctx: context.Context): void + preValidate(ctx: context.Context, app: App): void + } + interface ExternalAuth { /** - * PKCE indicates whether the provider can use the PKCE flow. + * ProxyRecord returns the proxied Record model. */ - pkce(): boolean + proxyRecord(): (Record) + } + interface ExternalAuth { /** - * SetPKCE toggles the state whether the provider can use the PKCE flow or not. + * SetProxyRecord loads the specified record model into the current proxy. */ - setPKCE(enable: boolean): void + setProxyRecord(record: Record): void + } + interface ExternalAuth { /** - * DisplayName usually returns provider name as it is officially written - * and it could be used directly in the UI. + * CollectionRef returns the "collectionRef" field value. */ - displayName(): string + collectionRef(): string + } + interface ExternalAuth { /** - * SetDisplayName sets the provider's display name. + * SetCollectionRef updates the "collectionRef" record field value. */ - setDisplayName(displayName: string): void + setCollectionRef(collectionId: string): void + } + interface ExternalAuth { /** - * Scopes returns the provider access permissions that will be requested. + * RecordRef returns the "recordRef" record field value. */ - scopes(): Array + recordRef(): string + } + interface ExternalAuth { /** - * SetScopes sets the provider access permissions that will be requested later. + * SetRecordRef updates the "recordRef" record field value. */ - setScopes(scopes: Array): void + setRecordRef(recordId: string): void + } + interface ExternalAuth { /** - * ClientId returns the provider client's app ID. + * Provider returns the "provider" record field value. */ - clientId(): string + provider(): string + } + interface ExternalAuth { /** - * SetClientId sets the provider client's ID. + * SetProvider updates the "provider" record field value. */ - setClientId(clientId: string): void + setProvider(provider: string): void + } + interface ExternalAuth { /** - * ClientSecret returns the provider client's app secret. + * Provider returns the "providerId" record field value. */ - clientSecret(): string + providerId(): string + } + interface ExternalAuth { /** - * SetClientSecret sets the provider client's app secret. + * SetProvider updates the "providerId" record field value. */ - setClientSecret(secret: string): void + setProviderId(providerId: string): void + } + interface ExternalAuth { /** - * RedirectUrl returns the end address to redirect the user - * going through the OAuth flow. + * Created returns the "created" record field value. */ - redirectUrl(): string + created(): types.DateTime + } + interface ExternalAuth { /** - * SetRedirectUrl sets the provider's RedirectUrl. + * Updated returns the "updated" record field value. */ - setRedirectUrl(url: string): void + updated(): types.DateTime + } + interface BaseApp { /** - * AuthUrl returns the provider's authorization service url. + * FindAllExternalAuthsByRecord returns all ExternalAuth models + * linked to the provided auth record. */ - authUrl(): string + findAllExternalAuthsByRecord(authRecord: Record): Array<(ExternalAuth | undefined)> + } + interface BaseApp { /** - * SetAuthUrl sets the provider's AuthUrl. + * FindAllExternalAuthsByCollection returns all ExternalAuth models + * linked to the provided auth collection. */ - setAuthUrl(url: string): void + findAllExternalAuthsByCollection(collection: Collection): Array<(ExternalAuth | undefined)> + } + interface BaseApp { /** - * TokenUrl returns the provider's token exchange service url. + * FindFirstExternalAuthByExpr returns the first available (the most recent created) + * ExternalAuth model that satisfies the non-nil expression. */ - tokenUrl(): string + findFirstExternalAuthByExpr(expr: dbx.Expression): (ExternalAuth) + } + /** + * FieldFactoryFunc defines a simple function to construct a specific Field instance. + */ + interface FieldFactoryFunc {(): Field } + /** + * Field defines a common interface that all Collection fields should implement. + */ + interface Field { + [key:string]: any; /** - * SetTokenUrl sets the provider's TokenUrl. + * GetId returns the field id. */ - setTokenUrl(url: string): void + getId(): string /** - * UserApiUrl returns the provider's user info api url. + * SetId changes the field id. */ - userApiUrl(): string + setId(id: string): void /** - * SetUserApiUrl sets the provider's UserApiUrl. + * GetName returns the field name. */ - setUserApiUrl(url: string): void + getName(): string /** - * Client returns an http client using the provided token. + * SetName changes the field name. */ - client(token: oauth2.Token): (any) + setName(name: string): void /** - * BuildAuthUrl returns a URL to the provider's consent page - * that asks for permissions for the required scopes explicitly. + * GetSystem returns the field system flag state. */ - buildAuthUrl(state: string, ...opts: oauth2.AuthCodeOption[]): string + getSystem(): boolean /** - * FetchToken converts an authorization code to token. + * SetSystem changes the field system flag state. */ - fetchToken(code: string, ...opts: oauth2.AuthCodeOption[]): (oauth2.Token) + setSystem(system: boolean): void /** - * FetchRawUserData requests and marshalizes into `result` the - * the OAuth user api response. + * GetHidden returns the field hidden flag state. */ - fetchRawUserData(token: oauth2.Token): string|Array + getHidden(): boolean /** - * FetchAuthUser is similar to FetchRawUserData, but normalizes and - * marshalizes the user api response into a standardized AuthUser struct. + * SetHidden changes the field hidden flag state. */ - fetchAuthUser(token: oauth2.Token): (AuthUser) - } -} - -/** - * Package sql provides a generic interface around SQL (or SQL-like) - * databases. - * - * The sql package must be used in conjunction with a database driver. - * See https://golang.org/s/sqldrivers for a list of drivers. - * - * Drivers that do not support context cancellation will not return until - * after the query is completed. - * - * For usage examples, see the wiki page at - * https://golang.org/s/sqlwiki. - */ -namespace sql { - /** - * TxOptions holds the transaction options to be used in [DB.BeginTx]. - */ - interface TxOptions { + setHidden(hidden: boolean): void /** - * Isolation is the transaction isolation level. - * If zero, the driver or database's default level is used. + * Type returns the unique type of the field. */ - isolation: IsolationLevel - readOnly: boolean - } - /** - * DB is a database handle representing a pool of zero or more - * underlying connections. It's safe for concurrent use by multiple - * goroutines. - * - * The sql package creates and frees connections automatically; it - * also maintains a free pool of idle connections. If the database has - * a concept of per-connection state, such state can be reliably observed - * within a transaction ([Tx]) or connection ([Conn]). Once [DB.Begin] is called, the - * returned [Tx] is bound to a single connection. Once [Tx.Commit] or - * [Tx.Rollback] is called on the transaction, that transaction's - * connection is returned to [DB]'s idle connection pool. The pool size - * can be controlled with [DB.SetMaxIdleConns]. - */ - interface DB { - } - interface DB { + type(): string /** - * PingContext verifies a connection to the database is still alive, - * establishing a connection if necessary. + * ColumnType returns the DB column definition of the field. */ - pingContext(ctx: context.Context): void - } - interface DB { + columnType(app: App): string /** - * Ping verifies a connection to the database is still alive, - * establishing a connection if necessary. + * PrepareValue returns a properly formatted field value based on the provided raw one. * - * Ping uses [context.Background] internally; to specify the context, use - * [DB.PingContext]. + * This method is also called on record construction to initialize its default field value. */ - ping(): void - } - interface DB { + prepareValue(record: Record, raw: any): any /** - * Close closes the database and prevents new queries from starting. - * Close then waits for all queries that have started processing on the server - * to finish. - * - * It is rare to Close a [DB], as the [DB] handle is meant to be - * long-lived and shared between many goroutines. + * ValidateSettings validates the current field value associated with the provided record. */ - close(): void - } - interface DB { + validateValue(ctx: context.Context, app: App, record: Record): void /** - * SetMaxIdleConns sets the maximum number of connections in the idle - * connection pool. - * - * If MaxOpenConns is greater than 0 but less than the new MaxIdleConns, - * then the new MaxIdleConns will be reduced to match the MaxOpenConns limit. - * - * If n <= 0, no idle connections are retained. - * - * The default max idle connections is currently 2. This may change in - * a future release. + * ValidateSettings validates the current field settings. */ - setMaxIdleConns(n: number): void + validateSettings(ctx: context.Context, app: App, collection: Collection): void } - interface DB { + /** + * MaxBodySizeCalculator defines an optional field interface for + * specifying the max size of a field value. + */ + interface MaxBodySizeCalculator { + [key:string]: any; /** - * SetMaxOpenConns sets the maximum number of open connections to the database. - * - * If MaxIdleConns is greater than 0 and the new MaxOpenConns is less than - * MaxIdleConns, then MaxIdleConns will be reduced to match the new - * MaxOpenConns limit. - * - * If n <= 0, then there is no limit on the number of open connections. - * The default is 0 (unlimited). + * CalculateMaxBodySize returns the approximate max body size of a field value. */ - setMaxOpenConns(n: number): void + calculateMaxBodySize(): number } - interface DB { + interface SetterFunc {(record: Record, raw: any): void } + /** + * SetterFinder defines a field interface for registering custom field value setters. + */ + interface SetterFinder { + [key:string]: any; /** - * SetConnMaxLifetime sets the maximum amount of time a connection may be reused. + * FindSetter returns a single field value setter function + * by performing pattern-like field matching using the specified key. * - * Expired connections may be closed lazily before reuse. + * The key is usually just the field name but it could also + * contains "modifier" characters based on which you can perform custom set operations + * (ex. "users+" could be mapped to a function that will append new user to the existing field value). * - * If d <= 0, connections are not closed due to a connection's age. + * Return nil if you want to fallback to the default field value setter. */ - setConnMaxLifetime(d: time.Duration): void + findSetter(key: string): SetterFunc } - interface DB { + interface GetterFunc {(record: Record): any } + /** + * GetterFinder defines a field interface for registering custom field value getters. + */ + interface GetterFinder { + [key:string]: any; /** - * SetConnMaxIdleTime sets the maximum amount of time a connection may be idle. + * FindGetter returns a single field value getter function + * by performing pattern-like field matching using the specified key. * - * Expired connections may be closed lazily before reuse. + * The key is usually just the field name but it could also + * contains "modifier" characters based on which you can perform custom get operations + * (ex. "description:excerpt" could be mapped to a function that will return an excerpt of the current field value). * - * If d <= 0, connections are not closed due to a connection's idle time. + * Return nil if you want to fallback to the default field value setter. */ - setConnMaxIdleTime(d: time.Duration): void + findGetter(key: string): GetterFunc } - interface DB { + /** + * DriverValuer defines a Field interface for exporting and formatting + * a field value for the database. + */ + interface DriverValuer { + [key:string]: any; /** - * Stats returns database statistics. + * DriverValue exports a single field value for persistence in the database. */ - stats(): DBStats + driverValue(record: Record): any } - interface DB { + /** + * MultiValuer defines a field interface that every multi-valued (eg. with MaxSelect) field has. + */ + interface MultiValuer { + [key:string]: any; /** - * PrepareContext creates a prepared statement for later queries or executions. - * Multiple queries or executions may be run concurrently from the - * returned statement. - * The caller must call the statement's [*Stmt.Close] method - * when the statement is no longer needed. - * - * The provided context is used for the preparation of the statement, not for the - * execution of the statement. + * IsMultiple checks whether the field is configured to support multiple or single values. */ - prepareContext(ctx: context.Context, query: string): (Stmt) + isMultiple(): boolean } - interface DB { + /** + * RecordInterceptor defines a field interface for reacting to various + * Record related operations (create, delete, validate, etc.). + */ + interface RecordInterceptor { + [key:string]: any; /** - * Prepare creates a prepared statement for later queries or executions. - * Multiple queries or executions may be run concurrently from the - * returned statement. - * The caller must call the statement's [*Stmt.Close] method - * when the statement is no longer needed. + * Interceptor is invoked when a specific record action occurs + * allowing you to perform extra validations and normalization + * (ex. uploading or deleting files). * - * Prepare uses [context.Background] internally; to specify the context, use - * [DB.PrepareContext]. + * Note that users must call actionFunc() manually if they want to + * execute the specific record action. */ - prepare(query: string): (Stmt) + intercept(ctx: context.Context, app: App, record: Record, actionName: string, actionFunc: () => void): void } - interface DB { + interface defaultFieldIdValidationRule { /** - * ExecContext executes a query without returning any rows. - * The args are for any placeholder parameters in the query. + * DefaultFieldIdValidationRule performs base validation on a field id value. */ - execContext(ctx: context.Context, query: string, ...args: any[]): Result + (value: any): void } - interface DB { + interface defaultFieldNameValidationRule { /** - * Exec executes a query without returning any rows. - * The args are for any placeholder parameters in the query. - * - * Exec uses [context.Background] internally; to specify the context, use - * [DB.ExecContext]. + * DefaultFieldIdValidationRule performs base validation on a field name value. */ - exec(query: string, ...args: any[]): Result + (value: any): void } - interface DB { + /** + * AutodateField defines an "autodate" type field, aka. + * field which datetime value could be auto set on record create/update. + * + * This field is usually used for defining timestamp fields like "created" and "updated". + * + * Requires either both or at least one of the OnCreate or OnUpdate options to be set. + */ + interface AutodateField { /** - * QueryContext executes a query that returns rows, typically a SELECT. - * The args are for any placeholder parameters in the query. + * Name (required) is the unique name of the field. */ - queryContext(ctx: context.Context, query: string, ...args: any[]): (Rows) - } - interface DB { + name: string /** - * Query executes a query that returns rows, typically a SELECT. - * The args are for any placeholder parameters in the query. + * Id is the unique stable field identifier. * - * Query uses [context.Background] internally; to specify the context, use - * [DB.QueryContext]. + * It is automatically generated from the name when adding to a collection FieldsList. */ - query(query: string, ...args: any[]): (Rows) - } - interface DB { + id: string /** - * QueryRowContext executes a query that is expected to return at most one row. - * QueryRowContext always returns a non-nil value. Errors are deferred until - * [Row]'s Scan method is called. - * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. - * Otherwise, [*Row.Scan] scans the first selected row and discards - * the rest. + * System prevents the renaming and removal of the field. */ - queryRowContext(ctx: context.Context, query: string, ...args: any[]): (Row) - } - interface DB { + system: boolean /** - * QueryRow executes a query that is expected to return at most one row. - * QueryRow always returns a non-nil value. Errors are deferred until - * [Row]'s Scan method is called. - * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. - * Otherwise, [*Row.Scan] scans the first selected row and discards - * the rest. - * - * QueryRow uses [context.Background] internally; to specify the context, use - * [DB.QueryRowContext]. + * Hidden hides the field from the API response. */ - queryRow(query: string, ...args: any[]): (Row) - } - interface DB { + hidden: boolean /** - * BeginTx starts a transaction. - * - * The provided context is used until the transaction is committed or rolled back. - * If the context is canceled, the sql package will roll back - * the transaction. [Tx.Commit] will return an error if the context provided to - * BeginTx is canceled. - * - * The provided [TxOptions] is optional and may be nil if defaults should be used. - * If a non-default isolation level is used that the driver doesn't support, - * an error will be returned. + * Presentable hints the Dashboard UI to use the underlying + * field record value in the relation preview label. */ - beginTx(ctx: context.Context, opts: TxOptions): (Tx) - } - interface DB { + presentable: boolean /** - * Begin starts a transaction. The default isolation level is dependent on - * the driver. - * - * Begin uses [context.Background] internally; to specify the context, use - * [DB.BeginTx]. + * OnCreate auto sets the current datetime as field value on record create. */ - begin(): (Tx) + onCreate: boolean + /** + * OnUpdate auto sets the current datetime as field value on record update. + */ + onUpdate: boolean } - interface DB { + interface AutodateField { /** - * Driver returns the database's underlying driver. + * Type implements [Field.Type] interface method. */ - driver(): any + type(): string } - interface DB { + interface AutodateField { /** - * Conn returns a single connection by either opening a new connection - * or returning an existing connection from the connection pool. Conn will - * block until either a connection is returned or ctx is canceled. - * Queries run on the same Conn will be run in the same database session. - * - * Every Conn must be returned to the database pool after use by - * calling [Conn.Close]. + * GetId implements [Field.GetId] interface method. */ - conn(ctx: context.Context): (Conn) + getId(): string } - /** - * Tx is an in-progress database transaction. - * - * A transaction must end with a call to [Tx.Commit] or [Tx.Rollback]. - * - * After a call to [Tx.Commit] or [Tx.Rollback], all operations on the - * transaction fail with [ErrTxDone]. - * - * The statements prepared for a transaction by calling - * the transaction's [Tx.Prepare] or [Tx.Stmt] methods are closed - * by the call to [Tx.Commit] or [Tx.Rollback]. - */ - interface Tx { + interface AutodateField { + /** + * SetId implements [Field.SetId] interface method. + */ + setId(id: string): void } - interface Tx { + interface AutodateField { /** - * Commit commits the transaction. + * GetName implements [Field.GetName] interface method. */ - commit(): void + getName(): string } - interface Tx { + interface AutodateField { /** - * Rollback aborts the transaction. + * SetName implements [Field.SetName] interface method. */ - rollback(): void + setName(name: string): void } - interface Tx { + interface AutodateField { /** - * PrepareContext creates a prepared statement for use within a transaction. - * - * The returned statement operates within the transaction and will be closed - * when the transaction has been committed or rolled back. - * - * To use an existing prepared statement on this transaction, see [Tx.Stmt]. - * - * The provided context will be used for the preparation of the context, not - * for the execution of the returned statement. The returned statement - * will run in the transaction context. + * GetSystem implements [Field.GetSystem] interface method. */ - prepareContext(ctx: context.Context, query: string): (Stmt) + getSystem(): boolean } - interface Tx { + interface AutodateField { /** - * Prepare creates a prepared statement for use within a transaction. - * - * The returned statement operates within the transaction and will be closed - * when the transaction has been committed or rolled back. - * - * To use an existing prepared statement on this transaction, see [Tx.Stmt]. - * - * Prepare uses [context.Background] internally; to specify the context, use - * [Tx.PrepareContext]. + * SetSystem implements [Field.SetSystem] interface method. */ - prepare(query: string): (Stmt) + setSystem(system: boolean): void } - interface Tx { + interface AutodateField { /** - * StmtContext returns a transaction-specific prepared statement from - * an existing statement. - * - * Example: - * - * ``` - * updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?") - * ... - * tx, err := db.Begin() - * ... - * res, err := tx.StmtContext(ctx, updateMoney).Exec(123.45, 98293203) - * ``` - * - * The provided context is used for the preparation of the statement, not for the - * execution of the statement. - * - * The returned statement operates within the transaction and will be closed - * when the transaction has been committed or rolled back. + * GetHidden implements [Field.GetHidden] interface method. */ - stmtContext(ctx: context.Context, stmt: Stmt): (Stmt) + getHidden(): boolean } - interface Tx { + interface AutodateField { /** - * Stmt returns a transaction-specific prepared statement from - * an existing statement. - * - * Example: - * - * ``` - * updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?") - * ... - * tx, err := db.Begin() - * ... - * res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203) - * ``` - * - * The returned statement operates within the transaction and will be closed - * when the transaction has been committed or rolled back. - * - * Stmt uses [context.Background] internally; to specify the context, use - * [Tx.StmtContext]. + * SetHidden implements [Field.SetHidden] interface method. */ - stmt(stmt: Stmt): (Stmt) + setHidden(hidden: boolean): void } - interface Tx { + interface AutodateField { /** - * ExecContext executes a query that doesn't return rows. - * For example: an INSERT and UPDATE. + * ColumnType implements [Field.ColumnType] interface method. */ - execContext(ctx: context.Context, query: string, ...args: any[]): Result + columnType(app: App): string } - interface Tx { + interface AutodateField { /** - * Exec executes a query that doesn't return rows. - * For example: an INSERT and UPDATE. - * - * Exec uses [context.Background] internally; to specify the context, use - * [Tx.ExecContext]. + * PrepareValue implements [Field.PrepareValue] interface method. */ - exec(query: string, ...args: any[]): Result + prepareValue(record: Record, raw: any): any } - interface Tx { + interface AutodateField { /** - * QueryContext executes a query that returns rows, typically a SELECT. + * ValidateValue implements [Field.ValidateValue] interface method. */ - queryContext(ctx: context.Context, query: string, ...args: any[]): (Rows) + validateValue(ctx: context.Context, app: App, record: Record): void } - interface Tx { + interface AutodateField { /** - * Query executes a query that returns rows, typically a SELECT. - * - * Query uses [context.Background] internally; to specify the context, use - * [Tx.QueryContext]. + * ValidateSettings implements [Field.ValidateSettings] interface method. */ - query(query: string, ...args: any[]): (Rows) + validateSettings(ctx: context.Context, app: App, collection: Collection): void } - interface Tx { + interface AutodateField { /** - * QueryRowContext executes a query that is expected to return at most one row. - * QueryRowContext always returns a non-nil value. Errors are deferred until - * [Row]'s Scan method is called. - * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. - * Otherwise, the [*Row.Scan] scans the first selected row and discards - * the rest. + * FindSetter implements the [SetterFinder] interface. */ - queryRowContext(ctx: context.Context, query: string, ...args: any[]): (Row) + findSetter(key: string): SetterFunc } - interface Tx { + interface AutodateField { /** - * QueryRow executes a query that is expected to return at most one row. - * QueryRow always returns a non-nil value. Errors are deferred until - * [Row]'s Scan method is called. - * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. - * Otherwise, the [*Row.Scan] scans the first selected row and discards - * the rest. - * - * QueryRow uses [context.Background] internally; to specify the context, use - * [Tx.QueryRowContext]. + * Intercept implements the [RecordInterceptor] interface. */ - queryRow(query: string, ...args: any[]): (Row) + intercept(ctx: context.Context, app: App, record: Record, actionName: string, actionFunc: () => void): void } /** - * Stmt is a prepared statement. - * A Stmt is safe for concurrent use by multiple goroutines. + * BoolField defines "bool" type field to store a single true/false value. * - * If a Stmt is prepared on a [Tx] or [Conn], it will be bound to a single - * underlying connection forever. If the [Tx] or [Conn] closes, the Stmt will - * become unusable and all operations will return an error. - * If a Stmt is prepared on a [DB], it will remain usable for the lifetime of the - * [DB]. When the Stmt needs to execute on a new underlying connection, it will - * prepare itself on the new connection automatically. + * The respective zero record field value is false. */ - interface Stmt { - } - interface Stmt { + interface BoolField { /** - * ExecContext executes a prepared statement with the given arguments and - * returns a [Result] summarizing the effect of the statement. + * Name (required) is the unique name of the field. */ - execContext(ctx: context.Context, ...args: any[]): Result - } - interface Stmt { + name: string /** - * Exec executes a prepared statement with the given arguments and - * returns a [Result] summarizing the effect of the statement. + * Id is the unique stable field identifier. * - * Exec uses [context.Background] internally; to specify the context, use - * [Stmt.ExecContext]. + * It is automatically generated from the name when adding to a collection FieldsList. */ - exec(...args: any[]): Result + id: string + /** + * System prevents the renaming and removal of the field. + */ + system: boolean + /** + * Hidden hides the field from the API response. + */ + hidden: boolean + /** + * Presentable hints the Dashboard UI to use the underlying + * field record value in the relation preview label. + */ + presentable: boolean + /** + * Required will require the field value to be always "true". + */ + required: boolean } - interface Stmt { + interface BoolField { /** - * QueryContext executes a prepared query statement with the given arguments - * and returns the query results as a [*Rows]. + * Type implements [Field.Type] interface method. */ - queryContext(ctx: context.Context, ...args: any[]): (Rows) + type(): string } - interface Stmt { + interface BoolField { /** - * Query executes a prepared query statement with the given arguments - * and returns the query results as a *Rows. - * - * Query uses [context.Background] internally; to specify the context, use - * [Stmt.QueryContext]. + * GetId implements [Field.GetId] interface method. */ - query(...args: any[]): (Rows) + getId(): string } - interface Stmt { + interface BoolField { /** - * QueryRowContext executes a prepared query statement with the given arguments. - * If an error occurs during the execution of the statement, that error will - * be returned by a call to Scan on the returned [*Row], which is always non-nil. - * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. - * Otherwise, the [*Row.Scan] scans the first selected row and discards - * the rest. + * SetId implements [Field.SetId] interface method. */ - queryRowContext(ctx: context.Context, ...args: any[]): (Row) + setId(id: string): void } - interface Stmt { + interface BoolField { /** - * QueryRow executes a prepared query statement with the given arguments. - * If an error occurs during the execution of the statement, that error will - * be returned by a call to Scan on the returned [*Row], which is always non-nil. - * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. - * Otherwise, the [*Row.Scan] scans the first selected row and discards - * the rest. - * - * Example usage: - * - * ``` - * var name string - * err := nameByUseridStmt.QueryRow(id).Scan(&name) - * ``` - * - * QueryRow uses [context.Background] internally; to specify the context, use - * [Stmt.QueryRowContext]. + * GetName implements [Field.GetName] interface method. */ - queryRow(...args: any[]): (Row) + getName(): string } - interface Stmt { + interface BoolField { /** - * Close closes the statement. + * SetName implements [Field.SetName] interface method. */ - close(): void + setName(name: string): void } - /** - * Rows is the result of a query. Its cursor starts before the first row - * of the result set. Use [Rows.Next] to advance from row to row. - */ - interface Rows { - } - interface Rows { + interface BoolField { /** - * Next prepares the next result row for reading with the [Rows.Scan] method. It - * returns true on success, or false if there is no next result row or an error - * happened while preparing it. [Rows.Err] should be consulted to distinguish between - * the two cases. - * - * Every call to [Rows.Scan], even the first one, must be preceded by a call to [Rows.Next]. + * GetSystem implements [Field.GetSystem] interface method. */ - next(): boolean + getSystem(): boolean } - interface Rows { + interface BoolField { /** - * NextResultSet prepares the next result set for reading. It reports whether - * there is further result sets, or false if there is no further result set - * or if there is an error advancing to it. The [Rows.Err] method should be consulted - * to distinguish between the two cases. - * - * After calling NextResultSet, the [Rows.Next] method should always be called before - * scanning. If there are further result sets they may not have rows in the result - * set. + * SetSystem implements [Field.SetSystem] interface method. */ - nextResultSet(): boolean + setSystem(system: boolean): void } - interface Rows { + interface BoolField { /** - * Err returns the error, if any, that was encountered during iteration. - * Err may be called after an explicit or implicit [Rows.Close]. + * GetHidden implements [Field.GetHidden] interface method. */ - err(): void + getHidden(): boolean } - interface Rows { + interface BoolField { /** - * Columns returns the column names. - * Columns returns an error if the rows are closed. + * SetHidden implements [Field.SetHidden] interface method. */ - columns(): Array + setHidden(hidden: boolean): void } - interface Rows { + interface BoolField { /** - * ColumnTypes returns column information such as column type, length, - * and nullable. Some information may not be available from some drivers. + * ColumnType implements [Field.ColumnType] interface method. */ - columnTypes(): Array<(ColumnType | undefined)> + columnType(app: App): string } - interface Rows { + interface BoolField { /** - * Scan copies the columns in the current row into the values pointed - * at by dest. The number of values in dest must be the same as the - * number of columns in [Rows]. - * - * Scan converts columns read from the database into the following - * common Go types and special types provided by the sql package: - * - * ``` - * *string - * *[]byte - * *int, *int8, *int16, *int32, *int64 - * *uint, *uint8, *uint16, *uint32, *uint64 - * *bool - * *float32, *float64 - * *interface{} - * *RawBytes - * *Rows (cursor value) - * any type implementing Scanner (see Scanner docs) - * ``` - * - * In the most simple case, if the type of the value from the source - * column is an integer, bool or string type T and dest is of type *T, - * Scan simply assigns the value through the pointer. - * - * Scan also converts between string and numeric types, as long as no - * information would be lost. While Scan stringifies all numbers - * scanned from numeric database columns into *string, scans into - * numeric types are checked for overflow. For example, a float64 with - * value 300 or a string with value "300" can scan into a uint16, but - * not into a uint8, though float64(255) or "255" can scan into a - * uint8. One exception is that scans of some float64 numbers to - * strings may lose information when stringifying. In general, scan - * floating point columns into *float64. - * - * If a dest argument has type *[]byte, Scan saves in that argument a - * copy of the corresponding data. The copy is owned by the caller and - * can be modified and held indefinitely. The copy can be avoided by - * using an argument of type [*RawBytes] instead; see the documentation - * for [RawBytes] for restrictions on its use. - * - * If an argument has type *interface{}, Scan copies the value - * provided by the underlying driver without conversion. When scanning - * from a source value of type []byte to *interface{}, a copy of the - * slice is made and the caller owns the result. - * - * Source values of type [time.Time] may be scanned into values of type - * *time.Time, *interface{}, *string, or *[]byte. When converting to - * the latter two, [time.RFC3339Nano] is used. - * - * Source values of type bool may be scanned into types *bool, - * *interface{}, *string, *[]byte, or [*RawBytes]. - * - * For scanning into *bool, the source may be true, false, 1, 0, or - * string inputs parseable by [strconv.ParseBool]. - * - * Scan can also convert a cursor returned from a query, such as - * "select cursor(select * from my_table) from dual", into a - * [*Rows] value that can itself be scanned from. The parent - * select query will close any cursor [*Rows] if the parent [*Rows] is closed. - * - * If any of the first arguments implementing [Scanner] returns an error, - * that error will be wrapped in the returned error. + * PrepareValue implements [Field.PrepareValue] interface method. */ - scan(...dest: any[]): void + prepareValue(record: Record, raw: any): any } - interface Rows { + interface BoolField { /** - * Close closes the [Rows], preventing further enumeration. If [Rows.Next] is called - * and returns false and there are no further result sets, - * the [Rows] are closed automatically and it will suffice to check the - * result of [Rows.Err]. Close is idempotent and does not affect the result of [Rows.Err]. + * ValidateValue implements [Field.ValidateValue] interface method. */ - close(): void + validateValue(ctx: context.Context, app: App, record: Record): void } - /** - * A Result summarizes an executed SQL command. - */ - interface Result { - [key:string]: any; - /** - * LastInsertId returns the integer generated by the database - * in response to a command. Typically this will be from an - * "auto increment" column when inserting a new row. Not all - * databases support this feature, and the syntax of such - * statements varies. - */ - lastInsertId(): number + interface BoolField { /** - * RowsAffected returns the number of rows affected by an - * update, insert, or delete. Not every database or database - * driver may support this. + * ValidateSettings implements [Field.ValidateSettings] interface method. */ - rowsAffected(): number + validateSettings(ctx: context.Context, app: App, collection: Collection): void } -} - -/** - * Package echo implements high performance, minimalist Go web framework. - * - * Example: - * - * ``` - * package main - * - * import ( - * "github.com/labstack/echo/v5" - * "github.com/labstack/echo/v5/middleware" - * "log" - * "net/http" - * ) - * - * // Handler - * func hello(c echo.Context) error { - * return c.String(http.StatusOK, "Hello, World!") - * } - * - * func main() { - * // Echo instance - * e := echo.New() - * - * // Middleware - * e.Use(middleware.Logger()) - * e.Use(middleware.Recover()) - * - * // Routes - * e.GET("/", hello) - * - * // Start server - * if err := e.Start(":8080"); err != http.ErrServerClosed { - * log.Fatal(err) - * } - * } - * ``` - * - * Learn more at https://echo.labstack.com - */ -namespace echo { /** - * Context represents the context of the current HTTP request. It holds request and - * response objects, path, path parameters, data and registered handler. + * DateField defines "date" type field to store a single [types.DateTime] value. + * + * The respective zero record field value is the zero [types.DateTime]. */ - interface Context { - [key:string]: any; - /** - * Request returns `*http.Request`. - */ - request(): (http.Request) - /** - * SetRequest sets `*http.Request`. - */ - setRequest(r: http.Request): void - /** - * SetResponse sets `*Response`. - */ - setResponse(r: Response): void - /** - * Response returns `*Response`. - */ - response(): (Response) - /** - * IsTLS returns true if HTTP connection is TLS otherwise false. - */ - isTLS(): boolean + interface DateField { /** - * IsWebSocket returns true if HTTP connection is WebSocket otherwise false. + * Name (required) is the unique name of the field. */ - isWebSocket(): boolean - /** - * Scheme returns the HTTP protocol scheme, `http` or `https`. - */ - scheme(): string + name: string /** - * RealIP returns the client's network address based on `X-Forwarded-For` - * or `X-Real-IP` request header. - * The behavior can be configured using `Echo#IPExtractor`. + * Id is the unique stable field identifier. + * + * It is automatically generated from the name when adding to a collection FieldsList. */ - realIP(): string + id: string /** - * RouteInfo returns current request route information. Method, Path, Name and params if they exist for matched route. - * In case of 404 (route not found) and 405 (method not allowed) RouteInfo returns generic struct for these cases. + * System prevents the renaming and removal of the field. */ - routeInfo(): RouteInfo + system: boolean /** - * Path returns the registered path for the handler. + * Hidden hides the field from the API response. */ - path(): string + hidden: boolean /** - * PathParam returns path parameter by name. + * Presentable hints the Dashboard UI to use the underlying + * field record value in the relation preview label. */ - pathParam(name: string): string + presentable: boolean /** - * PathParamDefault returns the path parameter or default value for the provided name. + * Min specifies the min allowed field value. * - * Notes for DefaultRouter implementation: - * Path parameter could be empty for cases like that: - * * route `/release-:version/bin` and request URL is `/release-/bin` - * * route `/api/:version/image.jpg` and request URL is `/api//image.jpg` - * but not when path parameter is last part of route path - * * route `/download/file.:ext` will not match request `/download/file.` + * Leave it empty to skip the validator. */ - pathParamDefault(name: string, defaultValue: string): string + min: types.DateTime /** - * PathParams returns path parameter values. + * Max specifies the max allowed field value. + * + * Leave it empty to skip the validator. */ - pathParams(): PathParams + max: types.DateTime /** - * SetPathParams sets path parameters for current request. + * Required will require the field value to be non-zero [types.DateTime]. */ - setPathParams(params: PathParams): void + required: boolean + } + interface DateField { /** - * QueryParam returns the query param for the provided name. + * Type implements [Field.Type] interface method. */ - queryParam(name: string): string + type(): string + } + interface DateField { /** - * QueryParamDefault returns the query param or default value for the provided name. + * GetId implements [Field.GetId] interface method. */ - queryParamDefault(name: string, defaultValue: string): string + getId(): string + } + interface DateField { /** - * QueryParams returns the query parameters as `url.Values`. + * SetId implements [Field.SetId] interface method. */ - queryParams(): url.Values + setId(id: string): void + } + interface DateField { /** - * QueryString returns the URL query string. + * GetName implements [Field.GetName] interface method. */ - queryString(): string + getName(): string + } + interface DateField { /** - * FormValue returns the form field value for the provided name. + * SetName implements [Field.SetName] interface method. */ - formValue(name: string): string + setName(name: string): void + } + interface DateField { /** - * FormValueDefault returns the form field value or default value for the provided name. + * GetSystem implements [Field.GetSystem] interface method. */ - formValueDefault(name: string, defaultValue: string): string + getSystem(): boolean + } + interface DateField { /** - * FormValues returns the form field values as `url.Values`. + * SetSystem implements [Field.SetSystem] interface method. */ - formValues(): url.Values + setSystem(system: boolean): void + } + interface DateField { /** - * FormFile returns the multipart form file for the provided name. + * GetHidden implements [Field.GetHidden] interface method. */ - formFile(name: string): (multipart.FileHeader) + getHidden(): boolean + } + interface DateField { /** - * MultipartForm returns the multipart form. + * SetHidden implements [Field.SetHidden] interface method. */ - multipartForm(): (multipart.Form) + setHidden(hidden: boolean): void + } + interface DateField { /** - * Cookie returns the named cookie provided in the request. + * ColumnType implements [Field.ColumnType] interface method. */ - cookie(name: string): (http.Cookie) + columnType(app: App): string + } + interface DateField { /** - * SetCookie adds a `Set-Cookie` header in HTTP response. + * PrepareValue implements [Field.PrepareValue] interface method. */ - setCookie(cookie: http.Cookie): void + prepareValue(record: Record, raw: any): any + } + interface DateField { /** - * Cookies returns the HTTP cookies sent with the request. + * ValidateValue implements [Field.ValidateValue] interface method. */ - cookies(): Array<(http.Cookie | undefined)> + validateValue(ctx: context.Context, app: App, record: Record): void + } + interface DateField { /** - * Get retrieves data from the context. + * ValidateSettings implements [Field.ValidateSettings] interface method. */ - get(key: string): { + validateSettings(ctx: context.Context, app: App, collection: Collection): void } + /** + * EditorField defines "editor" type field to store HTML formatted text. + * + * The respective zero record field value is empty string. + */ + interface EditorField { /** - * Set saves data in the context. + * Name (required) is the unique name of the field. */ - set(key: string, val: { - }): void + name: string /** - * Bind binds path params, query params and the request body into provided type `i`. The default binder - * binds body based on Content-Type header. + * Id is the unique stable field identifier. + * + * It is automatically generated from the name when adding to a collection FieldsList. */ - bind(i: { - }): void + id: string /** - * Validate validates provided `i`. It is usually called after `Context#Bind()`. - * Validator must be registered using `Echo#Validator`. + * System prevents the renaming and removal of the field. */ - validate(i: { - }): void + system: boolean /** - * Render renders a template with data and sends a text/html response with status - * code. Renderer must be registered using `Echo.Renderer`. + * Hidden hides the field from the API response. */ - render(code: number, name: string, data: { - }): void + hidden: boolean /** - * HTML sends an HTTP response with status code. + * Presentable hints the Dashboard UI to use the underlying + * field record value in the relation preview label. */ - html(code: number, html: string): void + presentable: boolean /** - * HTMLBlob sends an HTTP blob response with status code. + * MaxSize specifies the maximum size of the allowed field value (in bytes and up to 2^53-1). + * + * If zero, a default limit of ~5MB is applied. */ - htmlBlob(code: number, b: string|Array): void + maxSize: number /** - * String sends a string response with status code. + * ConvertURLs is usually used to instruct the editor whether to + * apply url conversion (eg. stripping the domain name in case the + * urls are using the same domain as the one where the editor is loaded). + * + * (see also https://www.tiny.cloud/docs/tinymce/6/url-handling/#convert_urls) */ - string(code: number, s: string): void + convertURLs: boolean /** - * JSON sends a JSON response with status code. + * Required will require the field value to be non-empty string. */ - json(code: number, i: { - }): void + required: boolean + } + interface EditorField { /** - * JSONPretty sends a pretty-print JSON with status code. + * Type implements [Field.Type] interface method. */ - jsonPretty(code: number, i: { - }, indent: string): void + type(): string + } + interface EditorField { /** - * JSONBlob sends a JSON blob response with status code. + * GetId implements [Field.GetId] interface method. */ - jsonBlob(code: number, b: string|Array): void + getId(): string + } + interface EditorField { /** - * JSONP sends a JSONP response with status code. It uses `callback` to construct - * the JSONP payload. + * SetId implements [Field.SetId] interface method. */ - jsonp(code: number, callback: string, i: { - }): void + setId(id: string): void + } + interface EditorField { /** - * JSONPBlob sends a JSONP blob response with status code. It uses `callback` - * to construct the JSONP payload. + * GetName implements [Field.GetName] interface method. */ - jsonpBlob(code: number, callback: string, b: string|Array): void + getName(): string + } + interface EditorField { /** - * XML sends an XML response with status code. + * SetName implements [Field.SetName] interface method. */ - xml(code: number, i: { - }): void + setName(name: string): void + } + interface EditorField { /** - * XMLPretty sends a pretty-print XML with status code. + * GetSystem implements [Field.GetSystem] interface method. */ - xmlPretty(code: number, i: { - }, indent: string): void + getSystem(): boolean + } + interface EditorField { /** - * XMLBlob sends an XML blob response with status code. + * SetSystem implements [Field.SetSystem] interface method. */ - xmlBlob(code: number, b: string|Array): void + setSystem(system: boolean): void + } + interface EditorField { /** - * Blob sends a blob response with status code and content type. + * GetHidden implements [Field.GetHidden] interface method. */ - blob(code: number, contentType: string, b: string|Array): void + getHidden(): boolean + } + interface EditorField { /** - * Stream sends a streaming response with status code and content type. + * SetHidden implements [Field.SetHidden] interface method. */ - stream(code: number, contentType: string, r: io.Reader): void + setHidden(hidden: boolean): void + } + interface EditorField { /** - * File sends a response with the content of the file. + * ColumnType implements [Field.ColumnType] interface method. */ - file(file: string): void + columnType(app: App): string + } + interface EditorField { /** - * FileFS sends a response with the content of the file from given filesystem. + * PrepareValue implements [Field.PrepareValue] interface method. */ - fileFS(file: string, filesystem: fs.FS): void + prepareValue(record: Record, raw: any): any + } + interface EditorField { /** - * Attachment sends a response as attachment, prompting client to save the - * file. + * ValidateValue implements [Field.ValidateValue] interface method. */ - attachment(file: string, name: string): void + validateValue(ctx: context.Context, app: App, record: Record): void + } + interface EditorField { /** - * Inline sends a response as inline, opening the file in the browser. + * ValidateSettings implements [Field.ValidateSettings] interface method. */ - inline(file: string, name: string): void + validateSettings(ctx: context.Context, app: App, collection: Collection): void + } + interface EditorField { /** - * NoContent sends a response with no body and a status code. + * CalculateMaxBodySize implements the [MaxBodySizeCalculator] interface. */ - noContent(code: number): void + calculateMaxBodySize(): number + } + /** + * EmailField defines "email" type field for storing a single email string address. + * + * The respective zero record field value is empty string. + */ + interface EmailField { /** - * Redirect redirects the request to a provided URL with status code. + * Name (required) is the unique name of the field. */ - redirect(code: number, url: string): void + name: string /** - * Error invokes the registered global HTTP error handler. Generally used by middleware. - * A side-effect of calling global error handler is that now Response has been committed (sent to the client) and - * middlewares up in chain can not change Response status code or Response body anymore. + * Id is the unique stable field identifier. * - * Avoid using this method in handlers as no middleware will be able to effectively handle errors after that. - * Instead of calling this method in handler return your error and let it be handled by middlewares or global error handler. + * It is automatically generated from the name when adding to a collection FieldsList. */ - error(err: Error): void + id: string /** - * Echo returns the `Echo` instance. - * - * WARNING: Remember that Echo public fields and methods are coroutine safe ONLY when you are NOT mutating them - * anywhere in your code after Echo server has started. + * System prevents the renaming and removal of the field. */ - echo(): (Echo) - } - // @ts-ignore - import stdContext = context - /** - * Echo is the top-level framework instance. - * - * Goroutine safety: Do not mutate Echo instance fields after server has started. Accessing these - * fields from handlers/middlewares and changing field values at the same time leads to data-races. - * Same rule applies to adding new routes after server has been started - Adding a route is not Goroutine safe action. - */ - interface Echo { + system: boolean /** - * NewContextFunc allows using custom context implementations, instead of default *echo.context + * Hidden hides the field from the API response. */ - newContextFunc: (e: Echo, pathParamAllocSize: number) => ServableContext - debug: boolean - httpErrorHandler: HTTPErrorHandler - binder: Binder - jsonSerializer: JSONSerializer - validator: Validator - renderer: Renderer - logger: Logger - ipExtractor: IPExtractor + hidden: boolean /** - * Filesystem is file system used by Static and File handlers to access files. - * Defaults to os.DirFS(".") - * - * When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary - * prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths - * including `assets/images` as their prefix. + * Presentable hints the Dashboard UI to use the underlying + * field record value in the relation preview label. */ - filesystem: fs.FS + presentable: boolean /** - * OnAddRoute is called when Echo adds new route to specific host router. Handler is called for every router - * and before route is added to the host router. + * ExceptDomains will require the email domain to NOT be included in the listed ones. + * + * This validator can be set only if OnlyDomains is empty. */ - onAddRoute: (host: string, route: Routable) => void - } - /** - * HandlerFunc defines a function to serve HTTP requests. - */ - interface HandlerFunc {(c: Context): void } - /** - * MiddlewareFunc defines a function to process middleware. - */ - interface MiddlewareFunc {(next: HandlerFunc): HandlerFunc } - interface Echo { + exceptDomains: Array /** - * NewContext returns a new Context instance. + * OnlyDomains will require the email domain to be included in the listed ones. * - * Note: both request and response can be left to nil as Echo.ServeHTTP will call c.Reset(req,resp) anyway - * these arguments are useful when creating context for tests and cases like that. + * This validator can be set only if ExceptDomains is empty. */ - newContext(r: http.Request, w: http.ResponseWriter): Context - } - interface Echo { + onlyDomains: Array /** - * Router returns the default router. + * Required will require the field value to be non-empty email string. */ - router(): Router + required: boolean } - interface Echo { + interface EmailField { /** - * Routers returns the new map of host => router. + * Type implements [Field.Type] interface method. */ - routers(): _TygojaDict + type(): string } - interface Echo { + interface EmailField { /** - * RouterFor returns Router for given host. When host is left empty the default router is returned. + * GetId implements [Field.GetId] interface method. */ - routerFor(host: string): [Router, boolean] + getId(): string } - interface Echo { + interface EmailField { /** - * ResetRouterCreator resets callback for creating new router instances. - * Note: current (default) router is immediately replaced with router created with creator func and vhost routers are cleared. + * SetId implements [Field.SetId] interface method. */ - resetRouterCreator(creator: (e: Echo) => Router): void + setId(id: string): void } - interface Echo { + interface EmailField { /** - * Pre adds middleware to the chain which is run before router tries to find matching route. - * Meaning middleware is executed even for 404 (not found) cases. + * GetName implements [Field.GetName] interface method. */ - pre(...middleware: MiddlewareFunc[]): void + getName(): string } - interface Echo { + interface EmailField { /** - * Use adds middleware to the chain which is run after router has found matching route and before route/request handler method is executed. + * SetName implements [Field.SetName] interface method. */ - use(...middleware: MiddlewareFunc[]): void + setName(name: string): void } - interface Echo { + interface EmailField { /** - * CONNECT registers a new CONNECT route for a path with matching handler in the - * router with optional route-level middleware. Panics on error. + * GetSystem implements [Field.GetSystem] interface method. */ - connect(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + getSystem(): boolean } - interface Echo { + interface EmailField { /** - * DELETE registers a new DELETE route for a path with matching handler in the router - * with optional route-level middleware. Panics on error. + * SetSystem implements [Field.SetSystem] interface method. */ - delete(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + setSystem(system: boolean): void } - interface Echo { + interface EmailField { /** - * GET registers a new GET route for a path with matching handler in the router - * with optional route-level middleware. Panics on error. + * GetHidden implements [Field.GetHidden] interface method. */ - get(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + getHidden(): boolean } - interface Echo { + interface EmailField { /** - * HEAD registers a new HEAD route for a path with matching handler in the - * router with optional route-level middleware. Panics on error. + * SetHidden implements [Field.SetHidden] interface method. */ - head(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + setHidden(hidden: boolean): void } - interface Echo { + interface EmailField { /** - * OPTIONS registers a new OPTIONS route for a path with matching handler in the - * router with optional route-level middleware. Panics on error. + * ColumnType implements [Field.ColumnType] interface method. */ - options(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + columnType(app: App): string } - interface Echo { + interface EmailField { /** - * PATCH registers a new PATCH route for a path with matching handler in the - * router with optional route-level middleware. Panics on error. + * PrepareValue implements [Field.PrepareValue] interface method. */ - patch(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + prepareValue(record: Record, raw: any): any } - interface Echo { + interface EmailField { /** - * POST registers a new POST route for a path with matching handler in the - * router with optional route-level middleware. Panics on error. + * ValidateValue implements [Field.ValidateValue] interface method. */ - post(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + validateValue(ctx: context.Context, app: App, record: Record): void } - interface Echo { + interface EmailField { /** - * PUT registers a new PUT route for a path with matching handler in the - * router with optional route-level middleware. Panics on error. + * ValidateSettings implements [Field.ValidateSettings] interface method. */ - put(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + validateSettings(ctx: context.Context, app: App, collection: Collection): void } - interface Echo { + /** + * FileField defines "file" type field for managing record file(s). + * + * Only the file name is stored as part of the record value. + * New files (aka. files to upload) are expected to be of *filesytem.File. + * + * If MaxSelect is not set or <= 1, then the field value is expected to be a single record id. + * + * If MaxSelect is > 1, then the field value is expected to be a slice of record ids. + * + * The respective zero record field value is either empty string (single) or empty string slice (multiple). + * + * --- + * + * The following additional setter keys are available: + * + * ``` + * - "fieldName+" - append one or more files to the existing record one. For example: + * + * // []string{"old1.txt", "old2.txt", "new1_ajkvass.txt", "new2_klhfnwd.txt"} + * record.Set("documents+", []*filesystem.File{new1, new2}) + * + * - "+fieldName" - prepend one or more files to the existing record one. For example: + * + * // []string{"new1_ajkvass.txt", "new2_klhfnwd.txt", "old1.txt", "old2.txt",} + * record.Set("+documents", []*filesystem.File{new1, new2}) + * + * - "fieldName-" - subtract/delete one or more files from the existing record one. For example: + * + * // []string{"old2.txt",} + * record.Set("documents-", "old1.txt") + * ``` + */ + interface FileField { /** - * TRACE registers a new TRACE route for a path with matching handler in the - * router with optional route-level middleware. Panics on error. + * Name (required) is the unique name of the field. */ - trace(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo - } - interface Echo { + name: string /** - * RouteNotFound registers a special-case route which is executed when no other route is found (i.e. HTTP 404 cases) - * for current request URL. - * Path supports static and named/any parameters just like other http method is defined. Generally path is ended with - * wildcard/match-any character (`/*`, `/download/*` etc). + * Id is the unique stable field identifier. * - * Example: `e.RouteNotFound("/*", func(c echo.Context) error { return c.NoContent(http.StatusNotFound) })` + * It is automatically generated from the name when adding to a collection FieldsList. */ - routeNotFound(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo - } - interface Echo { + id: string + /** + * System prevents the renaming and removal of the field. + */ + system: boolean + /** + * Hidden hides the field from the API response. + */ + hidden: boolean + /** + * Presentable hints the Dashboard UI to use the underlying + * field record value in the relation preview label. + */ + presentable: boolean + /** + * MaxSize specifies the maximum size of a single uploaded file (in bytes and up to 2^53-1). + * + * If zero, a default limit of 5MB is applied. + */ + maxSize: number + /** + * MaxSelect specifies the max allowed files. + * + * For multiple files the value must be > 1, otherwise fallbacks to single (default). + */ + maxSelect: number + /** + * MimeTypes specifies an optional list of the allowed file mime types. + * + * Leave it empty to disable the validator. + */ + mimeTypes: Array + /** + * Thumbs specifies an optional list of the supported thumbs for image based files. + * + * Each entry must be in one of the following formats: + * + * ``` + * - WxH (eg. 100x300) - crop to WxH viewbox (from center) + * - WxHt (eg. 100x300t) - crop to WxH viewbox (from top) + * - WxHb (eg. 100x300b) - crop to WxH viewbox (from bottom) + * - WxHf (eg. 100x300f) - fit inside a WxH viewbox (without cropping) + * - 0xH (eg. 0x300) - resize to H height preserving the aspect ratio + * - Wx0 (eg. 100x0) - resize to W width preserving the aspect ratio + * ``` + */ + thumbs: Array /** - * Any registers a new route for all HTTP methods (supported by Echo) and path with matching handler - * in the router with optional route-level middleware. + * Protected will require the users to provide a special file token to access the file. * - * Note: this method only adds specific set of supported HTTP methods as handler and is not true - * "catch-any-arbitrary-method" way of matching requests. + * Note that by default all files are publicly accessible. + * + * For the majority of the cases this is fine because by default + * all file names have random part appended to their name which + * need to be known by the user before accessing the file. + */ + protected: boolean + /** + * Required will require the field value to have at least one file. + */ + required: boolean + } + interface FileField { + /** + * Type implements [Field.Type] interface method. */ - any(path: string, handler: HandlerFunc, ...middleware: MiddlewareFunc[]): Routes + type(): string } - interface Echo { + interface FileField { /** - * Match registers a new route for multiple HTTP methods and path with matching - * handler in the router with optional route-level middleware. Panics on error. + * GetId implements [Field.GetId] interface method. */ - match(methods: Array, path: string, handler: HandlerFunc, ...middleware: MiddlewareFunc[]): Routes + getId(): string } - interface Echo { + interface FileField { /** - * Static registers a new route with path prefix to serve static files from the provided root directory. + * SetId implements [Field.SetId] interface method. */ - static(pathPrefix: string, fsRoot: string): RouteInfo + setId(id: string): void } - interface Echo { + interface FileField { /** - * StaticFS registers a new route with path prefix to serve static files from the provided file system. - * - * When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary - * prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths - * including `assets/images` as their prefix. + * GetName implements [Field.GetName] interface method. */ - staticFS(pathPrefix: string, filesystem: fs.FS): RouteInfo + getName(): string } - interface Echo { + interface FileField { /** - * FileFS registers a new route with path to serve file from the provided file system. + * SetName implements [Field.SetName] interface method. */ - fileFS(path: string, file: string, filesystem: fs.FS, ...m: MiddlewareFunc[]): RouteInfo + setName(name: string): void } - interface Echo { + interface FileField { /** - * File registers a new route with path to serve a static file with optional route-level middleware. Panics on error. + * GetSystem implements [Field.GetSystem] interface method. */ - file(path: string, file: string, ...middleware: MiddlewareFunc[]): RouteInfo + getSystem(): boolean } - interface Echo { + interface FileField { /** - * AddRoute registers a new Route with default host Router + * SetSystem implements [Field.SetSystem] interface method. */ - addRoute(route: Routable): RouteInfo + setSystem(system: boolean): void } - interface Echo { + interface FileField { /** - * Add registers a new route for an HTTP method and path with matching handler - * in the router with optional route-level middleware. + * GetHidden implements [Field.GetHidden] interface method. */ - add(method: string, path: string, handler: HandlerFunc, ...middleware: MiddlewareFunc[]): RouteInfo + getHidden(): boolean } - interface Echo { + interface FileField { /** - * Host creates a new router group for the provided host and optional host-level middleware. + * SetHidden implements [Field.SetHidden] interface method. */ - host(name: string, ...m: MiddlewareFunc[]): (Group) + setHidden(hidden: boolean): void } - interface Echo { + interface FileField { /** - * Group creates a new router group with prefix and optional group-level middleware. + * IsMultiple implements MultiValuer interface and checks whether the + * current field options support multiple values. */ - group(prefix: string, ...m: MiddlewareFunc[]): (Group) + isMultiple(): boolean } - interface Echo { + interface FileField { /** - * AcquireContext returns an empty `Context` instance from the pool. - * You must return the context by calling `ReleaseContext()`. + * ColumnType implements [Field.ColumnType] interface method. */ - acquireContext(): Context + columnType(app: App): string } - interface Echo { + interface FileField { /** - * ReleaseContext returns the `Context` instance back to the pool. - * You must call it after `AcquireContext()`. + * PrepareValue implements [Field.PrepareValue] interface method. */ - releaseContext(c: Context): void + prepareValue(record: Record, raw: any): any } - interface Echo { + interface FileField { /** - * ServeHTTP implements `http.Handler` interface, which serves HTTP requests. + * DriverValue implements the [DriverValuer] interface. */ - serveHTTP(w: http.ResponseWriter, r: http.Request): void + driverValue(record: Record): any } - interface Echo { + interface FileField { /** - * Start stars HTTP server on given address with Echo as a handler serving requests. The server can be shutdown by - * sending os.Interrupt signal with `ctrl+c`. - * - * Note: this method is created for use in examples/demos and is deliberately simple without providing configuration - * options. - * - * In need of customization use: - * - * ``` - * sc := echo.StartConfig{Address: ":8080"} - * if err := sc.Start(e); err != http.ErrServerClosed { - * log.Fatal(err) - * } - * ``` - * - * // or standard library `http.Server` + * ValidateSettings implements [Field.ValidateSettings] interface method. + */ + validateSettings(ctx: context.Context, app: App, collection: Collection): void + } + interface FileField { + /** + * ValidateValue implements [Field.ValidateValue] interface method. + */ + validateValue(ctx: context.Context, app: App, record: Record): void + } + interface FileField { + /** + * CalculateMaxBodySize implements the [MaxBodySizeCalculator] interface. + */ + calculateMaxBodySize(): number + } + interface FileField { + /** + * Intercept implements the [RecordInterceptor] interface. * - * ``` - * s := http.Server{Addr: ":8080", Handler: e} - * if err := s.ListenAndServe(); err != http.ErrServerClosed { - * log.Fatal(err) - * } - * ``` + * note: files delete after records deletion is handled globally by the app FileManager hook */ - start(address: string): void + intercept(ctx: context.Context, app: App, record: Record, actionName: string, actionFunc: () => void): void + } + interface FileField { + /** + * FindGetter implements the [GetterFinder] interface. + */ + findGetter(key: string): GetterFunc + } + interface FileField { + /** + * FindSetter implements the [SetterFinder] interface. + */ + findSetter(key: string): SetterFunc } -} - -/** - * Package exec runs external commands. It wraps os.StartProcess to make it - * easier to remap stdin and stdout, connect I/O with pipes, and do other - * adjustments. - * - * Unlike the "system" library call from C and other languages, the - * os/exec package intentionally does not invoke the system shell and - * does not expand any glob patterns or handle other expansions, - * pipelines, or redirections typically done by shells. The package - * behaves more like C's "exec" family of functions. To expand glob - * patterns, either call the shell directly, taking care to escape any - * dangerous input, or use the [path/filepath] package's Glob function. - * To expand environment variables, use package os's ExpandEnv. - * - * Note that the examples in this package assume a Unix system. - * They may not run on Windows, and they do not run in the Go Playground - * used by golang.org and godoc.org. - * - * # Executables in the current directory - * - * The functions [Command] and [LookPath] look for a program - * in the directories listed in the current path, following the - * conventions of the host operating system. - * Operating systems have for decades included the current - * directory in this search, sometimes implicitly and sometimes - * configured explicitly that way by default. - * Modern practice is that including the current directory - * is usually unexpected and often leads to security problems. - * - * To avoid those security problems, as of Go 1.19, this package will not resolve a program - * using an implicit or explicit path entry relative to the current directory. - * That is, if you run [LookPath]("go"), it will not successfully return - * ./go on Unix nor .\go.exe on Windows, no matter how the path is configured. - * Instead, if the usual path algorithms would result in that answer, - * these functions return an error err satisfying [errors.Is](err, [ErrDot]). - * - * For example, consider these two program snippets: - * - * ``` - * path, err := exec.LookPath("prog") - * if err != nil { - * log.Fatal(err) - * } - * use(path) - * ``` - * - * and - * - * ``` - * cmd := exec.Command("prog") - * if err := cmd.Run(); err != nil { - * log.Fatal(err) - * } - * ``` - * - * These will not find and run ./prog or .\prog.exe, - * no matter how the current path is configured. - * - * Code that always wants to run a program from the current directory - * can be rewritten to say "./prog" instead of "prog". - * - * Code that insists on including results from relative path entries - * can instead override the error using an errors.Is check: - * - * ``` - * path, err := exec.LookPath("prog") - * if errors.Is(err, exec.ErrDot) { - * err = nil - * } - * if err != nil { - * log.Fatal(err) - * } - * use(path) - * ``` - * - * and - * - * ``` - * cmd := exec.Command("prog") - * if errors.Is(cmd.Err, exec.ErrDot) { - * cmd.Err = nil - * } - * if err := cmd.Run(); err != nil { - * log.Fatal(err) - * } - * ``` - * - * Setting the environment variable GODEBUG=execerrdot=0 - * disables generation of ErrDot entirely, temporarily restoring the pre-Go 1.19 - * behavior for programs that are unable to apply more targeted fixes. - * A future version of Go may remove support for this variable. - * - * Before adding such overrides, make sure you understand the - * security implications of doing so. - * See https://go.dev/blog/path-security for more information. - */ -namespace exec { /** - * Cmd represents an external command being prepared or run. + * GeoPointField defines "geoPoint" type field for storing latitude and longitude GPS coordinates. * - * A Cmd cannot be reused after calling its [Cmd.Run], [Cmd.Output] or [Cmd.CombinedOutput] - * methods. + * You can set the record field value as [types.GeoPoint], map or serialized json object with lat-lon props. + * The stored value is always converted to [types.GeoPoint]. + * Nil, empty map, empty bytes slice, etc. results in zero [types.GeoPoint]. + * + * Examples of updating a record's GeoPointField value programmatically: + * + * ``` + * record.Set("location", types.GeoPoint{Lat: 123, Lon: 456}) + * record.Set("location", map[string]any{"lat":123, "lon":456}) + * record.Set("location", []byte(`{"lat":123, "lon":456}`) + * ``` */ - interface Cmd { + interface GeoPointField { /** - * Path is the path of the command to run. - * - * This is the only field that must be set to a non-zero - * value. If Path is relative, it is evaluated relative - * to Dir. + * Name (required) is the unique name of the field. */ - path: string + name: string /** - * Args holds command line arguments, including the command as Args[0]. - * If the Args field is empty or nil, Run uses {Path}. + * Id is the unique stable field identifier. * - * In typical use, both Path and Args are set by calling Command. + * It is automatically generated from the name when adding to a collection FieldsList. */ - args: Array + id: string /** - * Env specifies the environment of the process. - * Each entry is of the form "key=value". - * If Env is nil, the new process uses the current process's - * environment. - * If Env contains duplicate environment keys, only the last - * value in the slice for each duplicate key is used. - * As a special case on Windows, SYSTEMROOT is always added if - * missing and not explicitly set to the empty string. + * System prevents the renaming and removal of the field. */ - env: Array + system: boolean /** - * Dir specifies the working directory of the command. - * If Dir is the empty string, Run runs the command in the - * calling process's current directory. + * Hidden hides the field from the API response. */ - dir: string + hidden: boolean /** - * Stdin specifies the process's standard input. - * - * If Stdin is nil, the process reads from the null device (os.DevNull). - * - * If Stdin is an *os.File, the process's standard input is connected - * directly to that file. - * - * Otherwise, during the execution of the command a separate - * goroutine reads from Stdin and delivers that data to the command - * over a pipe. In this case, Wait does not complete until the goroutine - * stops copying, either because it has reached the end of Stdin - * (EOF or a read error), or because writing to the pipe returned an error, - * or because a nonzero WaitDelay was set and expired. + * Presentable hints the Dashboard UI to use the underlying + * field record value in the relation preview label. */ - stdin: io.Reader + presentable: boolean /** - * Stdout and Stderr specify the process's standard output and error. - * - * If either is nil, Run connects the corresponding file descriptor - * to the null device (os.DevNull). - * - * If either is an *os.File, the corresponding output from the process - * is connected directly to that file. - * - * Otherwise, during the execution of the command a separate goroutine - * reads from the process over a pipe and delivers that data to the - * corresponding Writer. In this case, Wait does not complete until the - * goroutine reaches EOF or encounters an error or a nonzero WaitDelay - * expires. - * - * If Stdout and Stderr are the same writer, and have a type that can - * be compared with ==, at most one goroutine at a time will call Write. + * Required will require the field coordinates to be non-zero (aka. not "Null Island"). */ - stdout: io.Writer - stderr: io.Writer + required: boolean + } + interface GeoPointField { /** - * ExtraFiles specifies additional open files to be inherited by the - * new process. It does not include standard input, standard output, or - * standard error. If non-nil, entry i becomes file descriptor 3+i. - * - * ExtraFiles is not supported on Windows. + * Type implements [Field.Type] interface method. */ - extraFiles: Array<(os.File | undefined)> + type(): string + } + interface GeoPointField { /** - * SysProcAttr holds optional, operating system-specific attributes. - * Run passes it to os.StartProcess as the os.ProcAttr's Sys field. + * GetId implements [Field.GetId] interface method. */ - sysProcAttr?: syscall.SysProcAttr + getId(): string + } + interface GeoPointField { /** - * Process is the underlying process, once started. + * SetId implements [Field.SetId] interface method. */ - process?: os.Process + setId(id: string): void + } + interface GeoPointField { /** - * ProcessState contains information about an exited process. - * If the process was started successfully, Wait or Run will - * populate its ProcessState when the command completes. + * GetName implements [Field.GetName] interface method. */ - processState?: os.ProcessState - err: Error // LookPath error, if any. + getName(): string + } + interface GeoPointField { /** - * If Cancel is non-nil, the command must have been created with - * CommandContext and Cancel will be called when the command's - * Context is done. By default, CommandContext sets Cancel to - * call the Kill method on the command's Process. - * - * Typically a custom Cancel will send a signal to the command's - * Process, but it may instead take other actions to initiate cancellation, - * such as closing a stdin or stdout pipe or sending a shutdown request on a - * network socket. - * - * If the command exits with a success status after Cancel is - * called, and Cancel does not return an error equivalent to - * os.ErrProcessDone, then Wait and similar methods will return a non-nil - * error: either an error wrapping the one returned by Cancel, - * or the error from the Context. - * (If the command exits with a non-success status, or Cancel - * returns an error that wraps os.ErrProcessDone, Wait and similar methods - * continue to return the command's usual exit status.) - * - * If Cancel is set to nil, nothing will happen immediately when the command's - * Context is done, but a nonzero WaitDelay will still take effect. That may - * be useful, for example, to work around deadlocks in commands that do not - * support shutdown signals but are expected to always finish quickly. - * - * Cancel will not be called if Start returns a non-nil error. + * SetName implements [Field.SetName] interface method. */ - cancel: () => void + setName(name: string): void + } + interface GeoPointField { /** - * If WaitDelay is non-zero, it bounds the time spent waiting on two sources - * of unexpected delay in Wait: a child process that fails to exit after the - * associated Context is canceled, and a child process that exits but leaves - * its I/O pipes unclosed. - * - * The WaitDelay timer starts when either the associated Context is done or a - * call to Wait observes that the child process has exited, whichever occurs - * first. When the delay has elapsed, the command shuts down the child process - * and/or its I/O pipes. - * - * If the child process has failed to exit — perhaps because it ignored or - * failed to receive a shutdown signal from a Cancel function, or because no - * Cancel function was set — then it will be terminated using os.Process.Kill. - * - * Then, if the I/O pipes communicating with the child process are still open, - * those pipes are closed in order to unblock any goroutines currently blocked - * on Read or Write calls. - * - * If pipes are closed due to WaitDelay, no Cancel call has occurred, - * and the command has otherwise exited with a successful status, Wait and - * similar methods will return ErrWaitDelay instead of nil. - * - * If WaitDelay is zero (the default), I/O pipes will be read until EOF, - * which might not occur until orphaned subprocesses of the command have - * also closed their descriptors for the pipes. + * GetSystem implements [Field.GetSystem] interface method. */ - waitDelay: time.Duration + getSystem(): boolean } - interface Cmd { + interface GeoPointField { /** - * String returns a human-readable description of c. - * It is intended only for debugging. - * In particular, it is not suitable for use as input to a shell. - * The output of String may vary across Go releases. + * SetSystem implements [Field.SetSystem] interface method. */ - string(): string + setSystem(system: boolean): void } - interface Cmd { + interface GeoPointField { /** - * Run starts the specified command and waits for it to complete. - * - * The returned error is nil if the command runs, has no problems - * copying stdin, stdout, and stderr, and exits with a zero exit - * status. - * - * If the command starts but does not complete successfully, the error is of - * type [*ExitError]. Other error types may be returned for other situations. - * - * If the calling goroutine has locked the operating system thread - * with [runtime.LockOSThread] and modified any inheritable OS-level - * thread state (for example, Linux or Plan 9 name spaces), the new - * process will inherit the caller's thread state. + * GetHidden implements [Field.GetHidden] interface method. */ - run(): void + getHidden(): boolean } - interface Cmd { + interface GeoPointField { /** - * Start starts the specified command but does not wait for it to complete. - * - * If Start returns successfully, the c.Process field will be set. - * - * After a successful call to Start the [Cmd.Wait] method must be called in - * order to release associated system resources. + * SetHidden implements [Field.SetHidden] interface method. */ - start(): void + setHidden(hidden: boolean): void } - interface Cmd { + interface GeoPointField { /** - * Wait waits for the command to exit and waits for any copying to - * stdin or copying from stdout or stderr to complete. - * - * The command must have been started by [Cmd.Start]. - * - * The returned error is nil if the command runs, has no problems - * copying stdin, stdout, and stderr, and exits with a zero exit - * status. - * - * If the command fails to run or doesn't complete successfully, the - * error is of type [*ExitError]. Other error types may be - * returned for I/O problems. - * - * If any of c.Stdin, c.Stdout or c.Stderr are not an [*os.File], Wait also waits - * for the respective I/O loop copying to or from the process to complete. - * - * Wait releases any resources associated with the [Cmd]. + * ColumnType implements [Field.ColumnType] interface method. */ - wait(): void + columnType(app: App): string } - interface Cmd { + interface GeoPointField { /** - * Output runs the command and returns its standard output. - * Any returned error will usually be of type [*ExitError]. - * If c.Stderr was nil, Output populates [ExitError.Stderr]. + * PrepareValue implements [Field.PrepareValue] interface method. */ - output(): string|Array + prepareValue(record: Record, raw: any): any } - interface Cmd { + interface GeoPointField { /** - * CombinedOutput runs the command and returns its combined standard - * output and standard error. + * ValidateValue implements [Field.ValidateValue] interface method. */ - combinedOutput(): string|Array + validateValue(ctx: context.Context, app: App, record: Record): void } - interface Cmd { + interface GeoPointField { /** - * StdinPipe returns a pipe that will be connected to the command's - * standard input when the command starts. - * The pipe will be closed automatically after [Cmd.Wait] sees the command exit. - * A caller need only call Close to force the pipe to close sooner. - * For example, if the command being run will not exit until standard input - * is closed, the caller must close the pipe. + * ValidateSettings implements [Field.ValidateSettings] interface method. */ - stdinPipe(): io.WriteCloser + validateSettings(ctx: context.Context, app: App, collection: Collection): void } - interface Cmd { + /** + * JSONField defines "json" type field for storing any serialized JSON value. + * + * The respective zero record field value is the zero [types.JSONRaw]. + */ + interface JSONField { /** - * StdoutPipe returns a pipe that will be connected to the command's - * standard output when the command starts. - * - * [Cmd.Wait] will close the pipe after seeing the command exit, so most callers - * need not close the pipe themselves. It is thus incorrect to call Wait - * before all reads from the pipe have completed. - * For the same reason, it is incorrect to call [Cmd.Run] when using StdoutPipe. - * See the example for idiomatic usage. + * Name (required) is the unique name of the field. */ - stdoutPipe(): io.ReadCloser - } - interface Cmd { + name: string /** - * StderrPipe returns a pipe that will be connected to the command's - * standard error when the command starts. + * Id is the unique stable field identifier. * - * [Cmd.Wait] will close the pipe after seeing the command exit, so most callers - * need not close the pipe themselves. It is thus incorrect to call Wait - * before all reads from the pipe have completed. - * For the same reason, it is incorrect to use [Cmd.Run] when using StderrPipe. - * See the StdoutPipe example for idiomatic usage. + * It is automatically generated from the name when adding to a collection FieldsList. */ - stderrPipe(): io.ReadCloser - } - interface Cmd { + id: string /** - * Environ returns a copy of the environment in which the command would be run - * as it is currently configured. + * System prevents the renaming and removal of the field. */ - environ(): Array - } -} - -/** - * Package blob provides an easy and portable way to interact with blobs - * within a storage location. Subpackages contain driver implementations of - * blob for supported services. - * - * See https://gocloud.dev/howto/blob/ for a detailed how-to guide. - * - * *blob.Bucket implements io/fs.FS and io/fs.SubFS, so it can be used with - * functions in that package. - * - * # Errors - * - * The errors returned from this package can be inspected in several ways: - * - * The Code function from gocloud.dev/gcerrors will return an error code, also - * defined in that package, when invoked on an error. - * - * The Bucket.ErrorAs method can retrieve the driver error underlying the returned - * error. - * - * # OpenCensus Integration - * - * OpenCensus supports tracing and metric collection for multiple languages and - * backend providers. See https://opencensus.io. - * - * This API collects OpenCensus traces and metrics for the following methods: - * ``` - * - Attributes - * - Copy - * - Delete - * - ListPage - * - NewRangeReader, from creation until the call to Close. (NewReader and ReadAll - * are included because they call NewRangeReader.) - * - NewWriter, from creation until the call to Close. - * ``` - * - * All trace and metric names begin with the package import path. - * The traces add the method name. - * For example, "gocloud.dev/blob/Attributes". - * The metrics are "completed_calls", a count of completed method calls by driver, - * method and status (error code); and "latency", a distribution of method latency - * by driver and method. - * For example, "gocloud.dev/blob/latency". - * - * It also collects the following metrics: - * ``` - * - gocloud.dev/blob/bytes_read: the total number of bytes read, by driver. - * - gocloud.dev/blob/bytes_written: the total number of bytes written, by driver. - * ``` - * - * To enable trace collection in your application, see "Configure Exporter" at - * https://opencensus.io/quickstart/go/tracing. - * To enable metric collection in your application, see "Exporting stats" at - * https://opencensus.io/quickstart/go/metrics. - */ -namespace blob { - /** - * Reader reads bytes from a blob. - * It implements io.ReadSeekCloser, and must be closed after - * reads are finished. - */ - interface Reader { - } - interface Reader { + system: boolean /** - * Read implements io.Reader (https://golang.org/pkg/io/#Reader). + * Hidden hides the field from the API response. */ - read(p: string|Array): number - } - interface Reader { + hidden: boolean /** - * Seek implements io.Seeker (https://golang.org/pkg/io/#Seeker). + * Presentable hints the Dashboard UI to use the underlying + * field record value in the relation preview label. */ - seek(offset: number, whence: number): number - } - interface Reader { + presentable: boolean /** - * Close implements io.Closer (https://golang.org/pkg/io/#Closer). + * MaxSize specifies the maximum size of the allowed field value (in bytes and up to 2^53-1). + * + * If zero, a default limit of 1MB is applied. */ - close(): void - } - interface Reader { + maxSize: number /** - * ContentType returns the MIME type of the blob. + * Required will require the field value to be non-empty JSON value + * (aka. not "null", `""`, "[]", "{}"). */ - contentType(): string + required: boolean } - interface Reader { + interface JSONField { /** - * ModTime returns the time the blob was last modified. + * Type implements [Field.Type] interface method. */ - modTime(): time.Time + type(): string } - interface Reader { + interface JSONField { /** - * Size returns the size of the blob content in bytes. + * GetId implements [Field.GetId] interface method. */ - size(): number + getId(): string } - interface Reader { + interface JSONField { /** - * As converts i to driver-specific types. - * See https://gocloud.dev/concepts/as/ for background information, the "As" - * examples in this package for examples, and the driver package - * documentation for the specific types supported for that driver. + * SetId implements [Field.SetId] interface method. */ - as(i: { - }): boolean + setId(id: string): void } - interface Reader { + interface JSONField { /** - * WriteTo reads from r and writes to w until there's no more data or - * an error occurs. - * The return value is the number of bytes written to w. - * - * It implements the io.WriterTo interface. + * GetName implements [Field.GetName] interface method. */ - writeTo(w: io.Writer): number + getName(): string } - /** - * Attributes contains attributes about a blob. - */ - interface Attributes { + interface JSONField { /** - * CacheControl specifies caching attributes that services may use - * when serving the blob. - * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control + * SetName implements [Field.SetName] interface method. */ - cacheControl: string + setName(name: string): void + } + interface JSONField { /** - * ContentDisposition specifies whether the blob content is expected to be - * displayed inline or as an attachment. - * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition + * GetSystem implements [Field.GetSystem] interface method. */ - contentDisposition: string + getSystem(): boolean + } + interface JSONField { /** - * ContentEncoding specifies the encoding used for the blob's content, if any. - * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding + * SetSystem implements [Field.SetSystem] interface method. */ - contentEncoding: string + setSystem(system: boolean): void + } + interface JSONField { /** - * ContentLanguage specifies the language used in the blob's content, if any. - * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Language + * GetHidden implements [Field.GetHidden] interface method. */ - contentLanguage: string + getHidden(): boolean + } + interface JSONField { /** - * ContentType is the MIME type of the blob. It will not be empty. - * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type + * SetHidden implements [Field.SetHidden] interface method. */ - contentType: string + setHidden(hidden: boolean): void + } + interface JSONField { /** - * Metadata holds key/value pairs associated with the blob. - * Keys are guaranteed to be in lowercase, even if the backend service - * has case-sensitive keys (although note that Metadata written via - * this package will always be lowercased). If there are duplicate - * case-insensitive keys (e.g., "foo" and "FOO"), only one value - * will be kept, and it is undefined which one. + * ColumnType implements [Field.ColumnType] interface method. */ - metadata: _TygojaDict + columnType(app: App): string + } + interface JSONField { /** - * CreateTime is the time the blob was created, if available. If not available, - * CreateTime will be the zero time. + * PrepareValue implements [Field.PrepareValue] interface method. */ - createTime: time.Time + prepareValue(record: Record, raw: any): any + } + interface JSONField { /** - * ModTime is the time the blob was last modified. + * ValidateValue implements [Field.ValidateValue] interface method. */ - modTime: time.Time + validateValue(ctx: context.Context, app: App, record: Record): void + } + interface JSONField { /** - * Size is the size of the blob's content in bytes. + * ValidateSettings implements [Field.ValidateSettings] interface method. */ - size: number + validateSettings(ctx: context.Context, app: App, collection: Collection): void + } + interface JSONField { /** - * MD5 is an MD5 hash of the blob contents or nil if not available. + * CalculateMaxBodySize implements the [MaxBodySizeCalculator] interface. */ - md5: string|Array - /** - * ETag for the blob; see https://en.wikipedia.org/wiki/HTTP_ETag. - */ - eTag: string - } - interface Attributes { - /** - * As converts i to driver-specific types. - * See https://gocloud.dev/concepts/as/ for background information, the "As" - * examples in this package for examples, and the driver package - * documentation for the specific types supported for that driver. - */ - as(i: { - }): boolean + calculateMaxBodySize(): number } /** - * ListObject represents a single blob returned from List. + * NumberField defines "number" type field for storing numeric (float64) value. + * + * The respective zero record field value is 0. + * + * The following additional setter keys are available: + * + * ``` + * - "fieldName+" - appends to the existing record value. For example: + * record.Set("total+", 5) + * - "fieldName-" - subtracts from the existing record value. For example: + * record.Set("total-", 5) + * ``` */ - interface ListObject { + interface NumberField { /** - * Key is the key for this blob. + * Name (required) is the unique name of the field. */ - key: string + name: string /** - * ModTime is the time the blob was last modified. + * Id is the unique stable field identifier. + * + * It is automatically generated from the name when adding to a collection FieldsList. */ - modTime: time.Time + id: string /** - * Size is the size of the blob's content in bytes. + * System prevents the renaming and removal of the field. */ - size: number + system: boolean /** - * MD5 is an MD5 hash of the blob contents or nil if not available. + * Hidden hides the field from the API response. */ - md5: string|Array + hidden: boolean /** - * IsDir indicates that this result represents a "directory" in the - * hierarchical namespace, ending in ListOptions.Delimiter. Key can be - * passed as ListOptions.Prefix to list items in the "directory". - * Fields other than Key and IsDir will not be set if IsDir is true. + * Presentable hints the Dashboard UI to use the underlying + * field record value in the relation preview label. */ - isDir: boolean - } - interface ListObject { + presentable: boolean /** - * As converts i to driver-specific types. - * See https://gocloud.dev/concepts/as/ for background information, the "As" - * examples in this package for examples, and the driver package - * documentation for the specific types supported for that driver. + * Min specifies the min allowed field value. + * + * Leave it nil to skip the validator. */ - as(i: { - }): boolean - } -} - -/** - * Package schema implements custom Schema and SchemaField datatypes - * for handling the Collection schema definitions. - */ -namespace schema { - // @ts-ignore - import validation = ozzo_validation - /** - * Schema defines a dynamic db schema as a slice of `SchemaField`s. - */ - interface Schema { - } - interface Schema { + min?: number /** - * Fields returns the registered schema fields. + * Max specifies the max allowed field value. + * + * Leave it nil to skip the validator. */ - fields(): Array<(SchemaField | undefined)> - } - interface Schema { + max?: number /** - * InitFieldsOptions calls `InitOptions()` for all schema fields. + * OnlyInt will require the field value to be integer. */ - initFieldsOptions(): void - } - interface Schema { + onlyInt: boolean /** - * Clone creates a deep clone of the current schema. + * Required will require the field value to be non-zero. */ - clone(): (Schema) + required: boolean } - interface Schema { + interface NumberField { /** - * AsMap returns a map with all registered schema field. - * The returned map is indexed with each field name. + * Type implements [Field.Type] interface method. */ - asMap(): _TygojaDict + type(): string } - interface Schema { + interface NumberField { /** - * GetFieldById returns a single field by its id. + * GetId implements [Field.GetId] interface method. */ - getFieldById(id: string): (SchemaField) + getId(): string } - interface Schema { + interface NumberField { /** - * GetFieldByName returns a single field by its name. + * SetId implements [Field.SetId] interface method. */ - getFieldByName(name: string): (SchemaField) + setId(id: string): void } - interface Schema { + interface NumberField { /** - * RemoveField removes a single schema field by its id. - * - * This method does nothing if field with `id` doesn't exist. + * GetName implements [Field.GetName] interface method. */ - removeField(id: string): void + getName(): string } - interface Schema { + interface NumberField { /** - * AddField registers the provided newField to the current schema. - * - * If field with `newField.Id` already exist, the existing field is - * replaced with the new one. - * - * Otherwise the new field is appended to the other schema fields. + * SetName implements [Field.SetName] interface method. */ - addField(newField: SchemaField): void + setName(name: string): void } - interface Schema { + interface NumberField { /** - * Validate makes Schema validatable by implementing [validation.Validatable] interface. - * - * Internally calls each individual field's validator and additionally - * checks for invalid renamed fields and field name duplications. + * GetSystem implements [Field.GetSystem] interface method. */ - validate(): void + getSystem(): boolean } - interface Schema { + interface NumberField { /** - * MarshalJSON implements the [json.Marshaler] interface. + * SetSystem implements [Field.SetSystem] interface method. */ - marshalJSON(): string|Array + setSystem(system: boolean): void } - interface Schema { + interface NumberField { /** - * UnmarshalJSON implements the [json.Unmarshaler] interface. - * - * On success, all schema field options are auto initialized. + * GetHidden implements [Field.GetHidden] interface method. */ - unmarshalJSON(data: string|Array): void + getHidden(): boolean } - interface Schema { + interface NumberField { /** - * Value implements the [driver.Valuer] interface. + * SetHidden implements [Field.SetHidden] interface method. */ - value(): any + setHidden(hidden: boolean): void } - interface Schema { + interface NumberField { /** - * Scan implements [sql.Scanner] interface to scan the provided value - * into the current Schema instance. + * ColumnType implements [Field.ColumnType] interface method. */ - scan(value: any): void - } -} - -/** - * Package models implements all PocketBase DB models and DTOs. - */ -namespace models { - type _subdxrsi = BaseModel - interface Admin extends _subdxrsi { - avatar: number - email: string - tokenKey: string - passwordHash: string - lastResetSentAt: types.DateTime + columnType(app: App): string } - interface Admin { + interface NumberField { /** - * TableName returns the Admin model SQL table name. + * PrepareValue implements [Field.PrepareValue] interface method. */ - tableName(): string + prepareValue(record: Record, raw: any): any } - interface Admin { + interface NumberField { /** - * ValidatePassword validates a plain password against the model's password. + * ValidateValue implements [Field.ValidateValue] interface method. */ - validatePassword(password: string): boolean + validateValue(ctx: context.Context, app: App, record: Record): void } - interface Admin { + interface NumberField { /** - * SetPassword sets cryptographically secure string to `model.Password`. - * - * Additionally this method also resets the LastResetSentAt and the TokenKey fields. + * ValidateSettings implements [Field.ValidateSettings] interface method. */ - setPassword(password: string): void + validateSettings(ctx: context.Context, app: App, collection: Collection): void } - interface Admin { + interface NumberField { /** - * RefreshTokenKey generates and sets new random token key. + * FindSetter implements the [SetterFinder] interface. */ - refreshTokenKey(): void + findSetter(key: string): SetterFunc } - // @ts-ignore - import validation = ozzo_validation - type _subzAftL = BaseModel - interface Collection extends _subzAftL { + /** + * PasswordField defines "password" type field for storing bcrypt hashed strings + * (usually used only internally for the "password" auth collection system field). + * + * If you want to set a direct bcrypt hash as record field value you can use the SetRaw method, for example: + * + * ``` + * // generates a bcrypt hash of "123456" and set it as field value + * // (record.GetString("password") returns the plain password until persisted, otherwise empty string) + * record.Set("password", "123456") + * + * // set directly a bcrypt hash of "123456" as field value + * // (record.GetString("password") returns empty string) + * record.SetRaw("password", "$2a$10$.5Elh8fgxypNUWhpUUr/xOa2sZm0VIaE0qWuGGl9otUfobb46T1Pq") + * ``` + * + * The following additional getter keys are available: + * + * ``` + * - "fieldName:hash" - returns the bcrypt hash string of the record field value (if any). For example: + * record.GetString("password:hash") + * ``` + */ + interface PasswordField { + /** + * Name (required) is the unique name of the field. + */ name: string - type: string + /** + * Id is the unique stable field identifier. + * + * It is automatically generated from the name when adding to a collection FieldsList. + */ + id: string + /** + * System prevents the renaming and removal of the field. + */ system: boolean - schema: schema.Schema - indexes: types.JsonArray /** - * rules + * Hidden hides the field from the API response. */ - listRule?: string - viewRule?: string - createRule?: string - updateRule?: string - deleteRule?: string - options: types.JsonMap - } - interface Collection { + hidden: boolean /** - * TableName returns the Collection model SQL table name. + * Presentable hints the Dashboard UI to use the underlying + * field record value in the relation preview label. */ - tableName(): string - } - interface Collection { + presentable: boolean /** - * BaseFilesPath returns the storage dir path used by the collection. + * Pattern specifies an optional regex pattern to match against the field value. + * + * Leave it empty to skip the pattern check. */ - baseFilesPath(): string - } - interface Collection { + pattern: string /** - * IsBase checks if the current collection has "base" type. + * Min specifies an optional required field string length. */ - isBase(): boolean - } - interface Collection { + min: number /** - * IsAuth checks if the current collection has "auth" type. + * Max specifies an optional required field string length. + * + * If zero, fallback to max 71 bytes. */ - isAuth(): boolean + max: number + /** + * Cost specifies the cost/weight/iteration/etc. bcrypt factor. + * + * If zero, fallback to [bcrypt.DefaultCost]. + * + * If explicitly set, must be between [bcrypt.MinCost] and [bcrypt.MaxCost]. + */ + cost: number + /** + * Required will require the field value to be non-empty string. + */ + required: boolean } - interface Collection { + interface PasswordField { /** - * IsView checks if the current collection has "view" type. + * Type implements [Field.Type] interface method. */ - isView(): boolean + type(): string } - interface Collection { + interface PasswordField { /** - * MarshalJSON implements the [json.Marshaler] interface. + * GetId implements [Field.GetId] interface method. */ - marshalJSON(): string|Array + getId(): string } - interface Collection { + interface PasswordField { /** - * BaseOptions decodes the current collection options and returns them - * as new [CollectionBaseOptions] instance. + * SetId implements [Field.SetId] interface method. */ - baseOptions(): CollectionBaseOptions + setId(id: string): void } - interface Collection { + interface PasswordField { /** - * AuthOptions decodes the current collection options and returns them - * as new [CollectionAuthOptions] instance. + * GetName implements [Field.GetName] interface method. */ - authOptions(): CollectionAuthOptions + getName(): string } - interface Collection { + interface PasswordField { /** - * ViewOptions decodes the current collection options and returns them - * as new [CollectionViewOptions] instance. + * SetName implements [Field.SetName] interface method. */ - viewOptions(): CollectionViewOptions + setName(name: string): void } - interface Collection { + interface PasswordField { /** - * NormalizeOptions updates the current collection options with a - * new normalized state based on the collection type. + * GetSystem implements [Field.GetSystem] interface method. */ - normalizeOptions(): void + getSystem(): boolean } - interface Collection { + interface PasswordField { /** - * DecodeOptions decodes the current collection options into the - * provided "result" (must be a pointer). + * SetSystem implements [Field.SetSystem] interface method. */ - decodeOptions(result: any): void + setSystem(system: boolean): void } - interface Collection { + interface PasswordField { /** - * SetOptions normalizes and unmarshals the specified options into m.Options. + * GetHidden implements [Field.GetHidden] interface method. */ - setOptions(typedOptions: any): void + getHidden(): boolean } - type _sublegJO = BaseModel - interface ExternalAuth extends _sublegJO { - collectionId: string - recordId: string - provider: string - providerId: string + interface PasswordField { + /** + * SetHidden implements [Field.SetHidden] interface method. + */ + setHidden(hidden: boolean): void } - interface ExternalAuth { - tableName(): string + interface PasswordField { + /** + * ColumnType implements [Field.ColumnType] interface method. + */ + columnType(app: App): string } - type _subFBhFW = BaseModel - interface Record extends _subFBhFW { + interface PasswordField { + /** + * DriverValue implements the [DriverValuer] interface. + */ + driverValue(record: Record): any } - interface Record { + interface PasswordField { /** - * TableName returns the table name associated to the current Record model. + * PrepareValue implements [Field.PrepareValue] interface method. */ - tableName(): string + prepareValue(record: Record, raw: any): any } - interface Record { + interface PasswordField { /** - * Collection returns the Collection model associated to the current Record model. + * ValidateValue implements [Field.ValidateValue] interface method. */ - collection(): (Collection) + validateValue(ctx: context.Context, app: App, record: Record): void } - interface Record { + interface PasswordField { /** - * OriginalCopy returns a copy of the current record model populated - * with its ORIGINAL data state (aka. the initially loaded) and - * everything else reset to the defaults. + * ValidateSettings implements [Field.ValidateSettings] interface method. */ - originalCopy(): (Record) + validateSettings(ctx: context.Context, app: App, collection: Collection): void } - interface Record { + interface PasswordField { /** - * CleanCopy returns a copy of the current record model populated only - * with its LATEST data state and everything else reset to the defaults. + * Intercept implements the [RecordInterceptor] interface. */ - cleanCopy(): (Record) + intercept(ctx: context.Context, app: App, record: Record, actionName: string, actionFunc: () => void): void } - interface Record { + interface PasswordField { /** - * Expand returns a shallow copy of the current Record model expand data. + * FindGetter implements the [GetterFinder] interface. */ - expand(): _TygojaDict + findGetter(key: string): GetterFunc } - interface Record { + interface PasswordField { /** - * SetExpand shallow copies the provided data to the current Record model's expand. + * FindSetter implements the [SetterFinder] interface. */ - setExpand(expand: _TygojaDict): void + findSetter(key: string): SetterFunc } - interface Record { + interface PasswordFieldValue { + lastError: Error + hash: string + plain: string + } + interface PasswordFieldValue { + validate(pass: string): boolean + } + /** + * RelationField defines "relation" type field for storing single or + * multiple collection record references. + * + * Requires the CollectionId option to be set. + * + * If MaxSelect is not set or <= 1, then the field value is expected to be a single record id. + * + * If MaxSelect is > 1, then the field value is expected to be a slice of record ids. + * + * The respective zero record field value is either empty string (single) or empty string slice (multiple). + * + * --- + * + * The following additional setter keys are available: + * + * ``` + * - "fieldName+" - append one or more values to the existing record one. For example: + * + * record.Set("categories+", []string{"new1", "new2"}) // []string{"old1", "old2", "new1", "new2"} + * + * - "+fieldName" - prepend one or more values to the existing record one. For example: + * + * record.Set("+categories", []string{"new1", "new2"}) // []string{"new1", "new2", "old1", "old2"} + * + * - "fieldName-" - subtract one or more values from the existing record one. For example: + * + * record.Set("categories-", "old1") // []string{"old2"} + * ``` + */ + interface RelationField { /** - * MergeExpand merges recursively the provided expand data into - * the current model's expand (if any). + * Name (required) is the unique name of the field. + */ + name: string + /** + * Id is the unique stable field identifier. * - * Note that if an expanded prop with the same key is a slice (old or new expand) - * then both old and new records will be merged into a new slice (aka. a :merge: [b,c] => [a,b,c]). - * Otherwise the "old" expanded record will be replace with the "new" one (aka. a :merge: aNew => aNew). + * It is automatically generated from the name when adding to a collection FieldsList. */ - mergeExpand(expand: _TygojaDict): void - } - interface Record { + id: string /** - * SchemaData returns a shallow copy ONLY of the defined record schema fields data. + * System prevents the renaming and removal of the field. */ - schemaData(): _TygojaDict - } - interface Record { + system: boolean /** - * UnknownData returns a shallow copy ONLY of the unknown record fields data, - * aka. fields that are neither one of the base and special system ones, - * nor defined by the collection schema. + * Hidden hides the field from the API response. */ - unknownData(): _TygojaDict - } - interface Record { + hidden: boolean /** - * IgnoreEmailVisibility toggles the flag to ignore the auth record email visibility check. + * Presentable hints the Dashboard UI to use the underlying + * field record value in the relation preview label. + */ + presentable: boolean + /** + * CollectionId is the id of the related collection. + */ + collectionId: string + /** + * CascadeDelete indicates whether the root model should be deleted + * in case of delete of all linked relations. + */ + cascadeDelete: boolean + /** + * MinSelect indicates the min number of allowed relation records + * that could be linked to the main model. + * + * No min limit is applied if it is zero or negative value. + */ + minSelect: number + /** + * MaxSelect indicates the max number of allowed relation records + * that could be linked to the main model. + * + * For multiple select the value must be > 1, otherwise fallbacks to single (default). + * + * If MinSelect is set, MaxSelect must be at least >= MinSelect. + */ + maxSelect: number + /** + * Required will require the field value to be non-empty. */ - ignoreEmailVisibility(state: boolean): void + required: boolean } - interface Record { + interface RelationField { /** - * WithUnknownData toggles the export/serialization of unknown data fields - * (false by default). + * Type implements [Field.Type] interface method. */ - withUnknownData(state: boolean): void + type(): string } - interface Record { + interface RelationField { /** - * Set sets the provided key-value data pair for the current Record model. - * - * If the record collection has field with name matching the provided "key", - * the value will be further normalized according to the field rules. + * GetId implements [Field.GetId] interface method. */ - set(key: string, value: any): void + getId(): string } - interface Record { + interface RelationField { /** - * Get returns a normalized single record model data value for "key". + * SetId implements [Field.SetId] interface method. */ - get(key: string): any + setId(id: string): void } - interface Record { + interface RelationField { /** - * GetBool returns the data value for "key" as a bool. + * GetName implements [Field.GetName] interface method. */ - getBool(key: string): boolean + getName(): string } - interface Record { + interface RelationField { /** - * GetString returns the data value for "key" as a string. + * SetName implements [Field.SetName] interface method. */ - getString(key: string): string + setName(name: string): void } - interface Record { + interface RelationField { /** - * GetInt returns the data value for "key" as an int. + * GetSystem implements [Field.GetSystem] interface method. */ - getInt(key: string): number + getSystem(): boolean } - interface Record { + interface RelationField { /** - * GetFloat returns the data value for "key" as a float64. + * SetSystem implements [Field.SetSystem] interface method. */ - getFloat(key: string): number + setSystem(system: boolean): void } - interface Record { + interface RelationField { /** - * GetTime returns the data value for "key" as a [time.Time] instance. + * GetHidden implements [Field.GetHidden] interface method. */ - getTime(key: string): time.Time + getHidden(): boolean } - interface Record { + interface RelationField { /** - * GetDateTime returns the data value for "key" as a DateTime instance. + * SetHidden implements [Field.SetHidden] interface method. */ - getDateTime(key: string): types.DateTime + setHidden(hidden: boolean): void } - interface Record { + interface RelationField { /** - * GetStringSlice returns the data value for "key" as a slice of unique strings. + * IsMultiple implements [MultiValuer] interface and checks whether the + * current field options support multiple values. */ - getStringSlice(key: string): Array + isMultiple(): boolean } - interface Record { + interface RelationField { /** - * ExpandedOne retrieves a single relation Record from the already - * loaded expand data of the current model. - * - * If the requested expand relation is multiple, this method returns - * only first available Record from the expanded relation. - * - * Returns nil if there is no such expand relation loaded. + * ColumnType implements [Field.ColumnType] interface method. */ - expandedOne(relField: string): (Record) + columnType(app: App): string } - interface Record { + interface RelationField { /** - * ExpandedAll retrieves a slice of relation Records from the already - * loaded expand data of the current model. - * - * If the requested expand relation is single, this method normalizes - * the return result and will wrap the single model as a slice. - * - * Returns nil slice if there is no such expand relation loaded. + * PrepareValue implements [Field.PrepareValue] interface method. */ - expandedAll(relField: string): Array<(Record | undefined)> + prepareValue(record: Record, raw: any): any } - interface Record { + interface RelationField { /** - * Retrieves the "key" json field value and unmarshals it into "result". - * - * Example - * - * ``` - * result := struct { - * FirstName string `json:"first_name"` - * }{} - * err := m.UnmarshalJSONField("my_field_name", &result) - * ``` + * DriverValue implements the [DriverValuer] interface. */ - unmarshalJSONField(key: string, result: any): void + driverValue(record: Record): any } - interface Record { + interface RelationField { /** - * BaseFilesPath returns the storage dir path used by the record. + * ValidateValue implements [Field.ValidateValue] interface method. */ - baseFilesPath(): string + validateValue(ctx: context.Context, app: App, record: Record): void } - interface Record { + interface RelationField { /** - * FindFileFieldByFile returns the first file type field for which - * any of the record's data contains the provided filename. + * ValidateSettings implements [Field.ValidateSettings] interface method. */ - findFileFieldByFile(filename: string): (schema.SchemaField) + validateSettings(ctx: context.Context, app: App, collection: Collection): void } - interface Record { + interface RelationField { /** - * Load bulk loads the provided data into the current Record model. + * FindSetter implements [SetterFinder] interface method. */ - load(data: _TygojaDict): void + findSetter(key: string): SetterFunc } - interface Record { + /** + * SelectField defines "select" type field for storing single or + * multiple string values from a predefined list. + * + * Requires the Values option to be set. + * + * If MaxSelect is not set or <= 1, then the field value is expected to be a single Values element. + * + * If MaxSelect is > 1, then the field value is expected to be a subset of Values slice. + * + * The respective zero record field value is either empty string (single) or empty string slice (multiple). + * + * --- + * + * The following additional setter keys are available: + * + * ``` + * - "fieldName+" - append one or more values to the existing record one. For example: + * + * record.Set("roles+", []string{"new1", "new2"}) // []string{"old1", "old2", "new1", "new2"} + * + * - "+fieldName" - prepend one or more values to the existing record one. For example: + * + * record.Set("+roles", []string{"new1", "new2"}) // []string{"new1", "new2", "old1", "old2"} + * + * - "fieldName-" - subtract one or more values from the existing record one. For example: + * + * record.Set("roles-", "old1") // []string{"old2"} + * ``` + */ + interface SelectField { /** - * ColumnValueMap implements [ColumnValueMapper] interface. + * Name (required) is the unique name of the field. */ - columnValueMap(): _TygojaDict - } - interface Record { + name: string /** - * PublicExport exports only the record fields that are safe to be public. + * Id is the unique stable field identifier. * - * For auth records, to force the export of the email field you need to set - * `m.IgnoreEmailVisibility(true)`. + * It is automatically generated from the name when adding to a collection FieldsList. */ - publicExport(): _TygojaDict - } - interface Record { + id: string /** - * MarshalJSON implements the [json.Marshaler] interface. + * System prevents the renaming and removal of the field. + */ + system: boolean + /** + * Hidden hides the field from the API response. + */ + hidden: boolean + /** + * Presentable hints the Dashboard UI to use the underlying + * field record value in the relation preview label. + */ + presentable: boolean + /** + * Values specifies the list of accepted values. + */ + values: Array + /** + * MaxSelect specifies the max allowed selected values. * - * Only the data exported by `PublicExport()` will be serialized. + * For multiple select the value must be > 1, otherwise fallbacks to single (default). */ - marshalJSON(): string|Array + maxSelect: number + /** + * Required will require the field value to be non-empty. + */ + required: boolean } - interface Record { + interface SelectField { /** - * UnmarshalJSON implements the [json.Unmarshaler] interface. + * Type implements [Field.Type] interface method. */ - unmarshalJSON(data: string|Array): void + type(): string } - interface Record { + interface SelectField { /** - * ReplaceModifers returns a new map with applied modifier - * values based on the current record and the specified data. - * - * The resolved modifier keys will be removed. - * - * Multiple modifiers will be applied one after another, - * while reusing the previous base key value result (eg. 1; -5; +2 => -2). - * - * Example usage: - * - * ``` - * newData := record.ReplaceModifers(data) - * // record: {"field": 10} - * // data: {"field+": 5} - * // newData: {"field": 15} - * ``` + * GetId implements [Field.GetId] interface method. */ - replaceModifers(data: _TygojaDict): _TygojaDict + getId(): string } - interface Record { + interface SelectField { /** - * Username returns the "username" auth record data value. + * SetId implements [Field.SetId] interface method. */ - username(): string + setId(id: string): void } - interface Record { + interface SelectField { /** - * SetUsername sets the "username" auth record data value. - * - * This method doesn't check whether the provided value is a valid username. - * - * Returns an error if the record is not from an auth collection. + * GetName implements [Field.GetName] interface method. */ - setUsername(username: string): void + getName(): string } - interface Record { + interface SelectField { /** - * Email returns the "email" auth record data value. + * SetName implements [Field.SetName] interface method. */ - email(): string + setName(name: string): void } - interface Record { + interface SelectField { /** - * SetEmail sets the "email" auth record data value. - * - * This method doesn't check whether the provided value is a valid email. - * - * Returns an error if the record is not from an auth collection. + * GetSystem implements [Field.GetSystem] interface method. */ - setEmail(email: string): void + getSystem(): boolean } - interface Record { + interface SelectField { /** - * Verified returns the "emailVisibility" auth record data value. + * SetSystem implements [Field.SetSystem] interface method. */ - emailVisibility(): boolean + setSystem(system: boolean): void } - interface Record { + interface SelectField { /** - * SetEmailVisibility sets the "emailVisibility" auth record data value. - * - * Returns an error if the record is not from an auth collection. + * GetHidden implements [Field.GetHidden] interface method. */ - setEmailVisibility(visible: boolean): void + getHidden(): boolean } - interface Record { + interface SelectField { /** - * Verified returns the "verified" auth record data value. + * SetHidden implements [Field.SetHidden] interface method. */ - verified(): boolean + setHidden(hidden: boolean): void } - interface Record { + interface SelectField { /** - * SetVerified sets the "verified" auth record data value. - * - * Returns an error if the record is not from an auth collection. + * IsMultiple implements [MultiValuer] interface and checks whether the + * current field options support multiple values. */ - setVerified(verified: boolean): void + isMultiple(): boolean } - interface Record { + interface SelectField { /** - * TokenKey returns the "tokenKey" auth record data value. + * ColumnType implements [Field.ColumnType] interface method. */ - tokenKey(): string + columnType(app: App): string } - interface Record { + interface SelectField { /** - * SetTokenKey sets the "tokenKey" auth record data value. - * - * Returns an error if the record is not from an auth collection. + * PrepareValue implements [Field.PrepareValue] interface method. */ - setTokenKey(key: string): void + prepareValue(record: Record, raw: any): any } - interface Record { + interface SelectField { /** - * RefreshTokenKey generates and sets new random auth record "tokenKey". - * - * Returns an error if the record is not from an auth collection. + * DriverValue implements the [DriverValuer] interface. */ - refreshTokenKey(): void + driverValue(record: Record): any } - interface Record { + interface SelectField { /** - * LastResetSentAt returns the "lastResentSentAt" auth record data value. + * ValidateValue implements [Field.ValidateValue] interface method. */ - lastResetSentAt(): types.DateTime + validateValue(ctx: context.Context, app: App, record: Record): void } - interface Record { + interface SelectField { /** - * SetLastResetSentAt sets the "lastResentSentAt" auth record data value. - * - * Returns an error if the record is not from an auth collection. + * ValidateSettings implements [Field.ValidateSettings] interface method. */ - setLastResetSentAt(dateTime: types.DateTime): void + validateSettings(ctx: context.Context, app: App, collection: Collection): void } - interface Record { + interface SelectField { /** - * LastVerificationSentAt returns the "lastVerificationSentAt" auth record data value. + * FindSetter implements the [SetterFinder] interface. */ - lastVerificationSentAt(): types.DateTime + findSetter(key: string): SetterFunc } - interface Record { + /** + * TextField defines "text" type field for storing any string value. + * + * The respective zero record field value is empty string. + * + * The following additional setter keys are available: + * + * - "fieldName:autogenerate" - autogenerate field value if AutogeneratePattern is set. For example: + * + * ``` + * record.Set("slug:autogenerate", "") // [random value] + * record.Set("slug:autogenerate", "abc-") // abc-[random value] + * ``` + */ + interface TextField { /** - * SetLastVerificationSentAt sets an "lastVerificationSentAt" auth record data value. + * Name (required) is the unique name of the field. + */ + name: string + /** + * Id is the unique stable field identifier. * - * Returns an error if the record is not from an auth collection. + * It is automatically generated from the name when adding to a collection FieldsList. */ - setLastVerificationSentAt(dateTime: types.DateTime): void - } - interface Record { + id: string /** - * LastLoginAlertSentAt returns the "lastLoginAlertSentAt" auth record data value. + * System prevents the renaming and removal of the field. */ - lastLoginAlertSentAt(): types.DateTime - } - interface Record { + system: boolean + /** + * Hidden hides the field from the API response. + */ + hidden: boolean /** - * SetLastLoginAlertSentAt sets an "lastLoginAlertSentAt" auth record data value. + * Presentable hints the Dashboard UI to use the underlying + * field record value in the relation preview label. + */ + presentable: boolean + /** + * Min specifies the minimum required string characters. * - * Returns an error if the record is not from an auth collection. + * if zero value, no min limit is applied. */ - setLastLoginAlertSentAt(dateTime: types.DateTime): void - } - interface Record { + min: number /** - * PasswordHash returns the "passwordHash" auth record data value. + * Max specifies the maximum allowed string characters. + * + * If zero, a default limit of 5000 is applied. */ - passwordHash(): string - } - interface Record { + max: number /** - * ValidatePassword validates a plain password against the auth record password. + * Pattern specifies an optional regex pattern to match against the field value. * - * Returns false if the password is incorrect or record is not from an auth collection. + * Leave it empty to skip the pattern check. */ - validatePassword(password: string): boolean - } - interface Record { + pattern: string /** - * SetPassword sets cryptographically secure string to the auth record "password" field. - * This method also resets the "lastResetSentAt" and the "tokenKey" fields. + * AutogeneratePattern specifies an optional regex pattern that could + * be used to generate random string from it and set it automatically + * on record create if no explicit value is set or when the `:autogenerate` modifier is used. * - * Returns an error if the record is not from an auth collection or - * an empty password is provided. + * Note: the generated value still needs to satisfy min, max, pattern (if set) */ - setPassword(password: string): void + autogeneratePattern: string + /** + * Required will require the field value to be non-empty string. + */ + required: boolean + /** + * PrimaryKey will mark the field as primary key. + * + * A single collection can have only 1 field marked as primary key. + */ + primaryKey: boolean } - /** - * RequestInfo defines a HTTP request data struct, usually used - * as part of the `@request.*` filter resolver. - */ - interface RequestInfo { - context: string - query: _TygojaDict - data: _TygojaDict - headers: _TygojaDict - authRecord?: Record - admin?: Admin - method: string + interface TextField { + /** + * Type implements [Field.Type] interface method. + */ + type(): string } - interface RequestInfo { + interface TextField { /** - * HasModifierDataKeys loosely checks if the current struct has any modifier Data keys. + * GetId implements [Field.GetId] interface method. */ - hasModifierDataKeys(): boolean + getId(): string } -} - -namespace settings { - // @ts-ignore - import validation = ozzo_validation - /** - * Settings defines common app configuration options. - */ - interface Settings { - meta: MetaConfig - logs: LogsConfig - smtp: SmtpConfig - s3: S3Config - backups: BackupsConfig - adminAuthToken: TokenConfig - adminPasswordResetToken: TokenConfig - adminFileToken: TokenConfig - recordAuthToken: TokenConfig - recordPasswordResetToken: TokenConfig - recordEmailChangeToken: TokenConfig - recordVerificationToken: TokenConfig - recordFileToken: TokenConfig - /** - * Deprecated: Will be removed in v0.9+ - */ - emailAuth: EmailAuthConfig - googleAuth: AuthProviderConfig - facebookAuth: AuthProviderConfig - githubAuth: AuthProviderConfig - gitlabAuth: AuthProviderConfig - discordAuth: AuthProviderConfig - twitterAuth: AuthProviderConfig - microsoftAuth: AuthProviderConfig - spotifyAuth: AuthProviderConfig - kakaoAuth: AuthProviderConfig - twitchAuth: AuthProviderConfig - stravaAuth: AuthProviderConfig - giteeAuth: AuthProviderConfig - livechatAuth: AuthProviderConfig - giteaAuth: AuthProviderConfig - oidcAuth: AuthProviderConfig - oidc2Auth: AuthProviderConfig - oidc3Auth: AuthProviderConfig - appleAuth: AuthProviderConfig - instagramAuth: AuthProviderConfig - vkAuth: AuthProviderConfig - yandexAuth: AuthProviderConfig - patreonAuth: AuthProviderConfig - mailcowAuth: AuthProviderConfig - bitbucketAuth: AuthProviderConfig - planningcenterAuth: AuthProviderConfig + interface TextField { + /** + * SetId implements [Field.SetId] interface method. + */ + setId(id: string): void } - interface Settings { + interface TextField { /** - * Validate makes Settings validatable by implementing [validation.Validatable] interface. + * GetName implements [Field.GetName] interface method. */ - validate(): void + getName(): string } - interface Settings { + interface TextField { /** - * Merge merges `other` settings into the current one. + * SetName implements [Field.SetName] interface method. */ - merge(other: Settings): void + setName(name: string): void } - interface Settings { + interface TextField { /** - * Clone creates a new deep copy of the current settings. + * GetSystem implements [Field.GetSystem] interface method. */ - clone(): (Settings) + getSystem(): boolean } - interface Settings { + interface TextField { /** - * RedactClone creates a new deep copy of the current settings, - * while replacing the secret values with `******`. + * SetSystem implements [Field.SetSystem] interface method. */ - redactClone(): (Settings) + setSystem(system: boolean): void } - interface Settings { + interface TextField { /** - * NamedAuthProviderConfigs returns a map with all registered OAuth2 - * provider configurations (indexed by their name identifier). + * GetHidden implements [Field.GetHidden] interface method. */ - namedAuthProviderConfigs(): _TygojaDict + getHidden(): boolean } -} - -/** - * Package daos handles common PocketBase DB model manipulations. - * - * Think of daos as DB repository and service layer in one. - */ -namespace daos { - interface Dao { + interface TextField { /** - * AdminQuery returns a new Admin select query. + * SetHidden implements [Field.SetHidden] interface method. */ - adminQuery(): (dbx.SelectQuery) + setHidden(hidden: boolean): void } - interface Dao { + interface TextField { /** - * FindAdminById finds the admin with the provided id. + * ColumnType implements [Field.ColumnType] interface method. */ - findAdminById(id: string): (models.Admin) + columnType(app: App): string } - interface Dao { + interface TextField { /** - * FindAdminByEmail finds the admin with the provided email address. + * PrepareValue implements [Field.PrepareValue] interface method. */ - findAdminByEmail(email: string): (models.Admin) + prepareValue(record: Record, raw: any): any } - interface Dao { + interface TextField { /** - * FindAdminByToken finds the admin associated with the provided JWT. - * - * Returns an error if the JWT is invalid or expired. + * ValidateValue implements [Field.ValidateValue] interface method. */ - findAdminByToken(token: string, baseTokenKey: string): (models.Admin) + validateValue(ctx: context.Context, app: App, record: Record): void } - interface Dao { + interface TextField { /** - * TotalAdmins returns the number of existing admin records. + * ValidatePlainValue validates the provided string against the field options. */ - totalAdmins(): number + validatePlainValue(value: string): void } - interface Dao { + interface TextField { /** - * IsAdminEmailUnique checks if the provided email address is not - * already in use by other admins. + * ValidateSettings implements [Field.ValidateSettings] interface method. */ - isAdminEmailUnique(email: string, ...excludeIds: string[]): boolean + validateSettings(ctx: context.Context, app: App, collection: Collection): void } - interface Dao { + interface TextField { /** - * DeleteAdmin deletes the provided Admin model. - * - * Returns an error if there is only 1 admin. + * Intercept implements the [RecordInterceptor] interface. */ - deleteAdmin(admin: models.Admin): void + intercept(ctx: context.Context, app: App, record: Record, actionName: string, actionFunc: () => void): void } - interface Dao { + interface TextField { /** - * SaveAdmin upserts the provided Admin model. + * FindSetter implements the [SetterFinder] interface. */ - saveAdmin(admin: models.Admin): void + findSetter(key: string): SetterFunc } /** - * Dao handles various db operations. + * URLField defines "url" type field for storing a single URL string value. * - * You can think of Dao as a repository and service layer in one. + * The respective zero record field value is empty string. */ - interface Dao { + interface URLField { /** - * MaxLockRetries specifies the default max "database is locked" auto retry attempts. + * Name (required) is the unique name of the field. */ - maxLockRetries: number + name: string /** - * ModelQueryTimeout is the default max duration of a running ModelQuery(). + * Id is the unique stable field identifier. * - * This field has no effect if an explicit query context is already specified. + * It is automatically generated from the name when adding to a collection FieldsList. */ - modelQueryTimeout: time.Duration + id: string /** - * write hooks + * System prevents the renaming and removal of the field. */ - beforeCreateFunc: (eventDao: Dao, m: models.Model, action: () => void) => void - afterCreateFunc: (eventDao: Dao, m: models.Model) => void - beforeUpdateFunc: (eventDao: Dao, m: models.Model, action: () => void) => void - afterUpdateFunc: (eventDao: Dao, m: models.Model) => void - beforeDeleteFunc: (eventDao: Dao, m: models.Model, action: () => void) => void - afterDeleteFunc: (eventDao: Dao, m: models.Model) => void - } - interface Dao { + system: boolean /** - * DB returns the default dao db builder (*dbx.DB or *dbx.TX). - * - * Currently the default db builder is dao.concurrentDB but that may change in the future. + * Hidden hides the field from the API response. */ - db(): dbx.Builder - } - interface Dao { + hidden: boolean /** - * ConcurrentDB returns the dao concurrent (aka. multiple open connections) - * db builder (*dbx.DB or *dbx.TX). + * Presentable hints the Dashboard UI to use the underlying + * field record value in the relation preview label. + */ + presentable: boolean + /** + * ExceptDomains will require the URL domain to NOT be included in the listed ones. * - * In a transaction the concurrentDB and nonconcurrentDB refer to the same *dbx.TX instance. + * This validator can be set only if OnlyDomains is empty. */ - concurrentDB(): dbx.Builder - } - interface Dao { + exceptDomains: Array /** - * NonconcurrentDB returns the dao nonconcurrent (aka. single open connection) - * db builder (*dbx.DB or *dbx.TX). + * OnlyDomains will require the URL domain to be included in the listed ones. * - * In a transaction the concurrentDB and nonconcurrentDB refer to the same *dbx.TX instance. + * This validator can be set only if ExceptDomains is empty. */ - nonconcurrentDB(): dbx.Builder - } - interface Dao { + onlyDomains: Array /** - * Clone returns a new Dao with the same configuration options as the current one. + * Required will require the field value to be non-empty URL string. */ - clone(): (Dao) + required: boolean } - interface Dao { + interface URLField { /** - * WithoutHooks returns a new Dao with the same configuration options - * as the current one, but without create/update/delete hooks. + * Type implements [Field.Type] interface method. */ - withoutHooks(): (Dao) + type(): string } - interface Dao { + interface URLField { /** - * ModelQuery creates a new preconfigured select query with preset - * SELECT, FROM and other common fields based on the provided model. + * GetId implements [Field.GetId] interface method. */ - modelQuery(m: models.Model): (dbx.SelectQuery) + getId(): string } - interface Dao { + interface URLField { /** - * FindById finds a single db record with the specified id and - * scans the result into m. + * SetId implements [Field.SetId] interface method. */ - findById(m: models.Model, id: string): void + setId(id: string): void } - interface Dao { + interface URLField { /** - * RunInTransaction wraps fn into a transaction. - * - * It is safe to nest RunInTransaction calls as long as you use the txDao. + * GetName implements [Field.GetName] interface method. */ - runInTransaction(fn: (txDao: Dao) => void): void + getName(): string } - interface Dao { + interface URLField { /** - * Delete deletes the provided model. + * SetName implements [Field.SetName] interface method. */ - delete(m: models.Model): void + setName(name: string): void } - interface Dao { + interface URLField { /** - * Save persists the provided model in the database. - * - * If m.IsNew() is true, the method will perform a create, otherwise an update. - * To explicitly mark a model for update you can use m.MarkAsNotNew(). + * GetSystem implements [Field.GetSystem] interface method. */ - save(m: models.Model): void + getSystem(): boolean } - interface Dao { + interface URLField { /** - * CollectionQuery returns a new Collection select query. + * SetSystem implements [Field.SetSystem] interface method. */ - collectionQuery(): (dbx.SelectQuery) + setSystem(system: boolean): void } - interface Dao { + interface URLField { /** - * FindCollectionsByType finds all collections by the given type. + * GetHidden implements [Field.GetHidden] interface method. */ - findCollectionsByType(collectionType: string): Array<(models.Collection | undefined)> + getHidden(): boolean } - interface Dao { + interface URLField { /** - * FindCollectionByNameOrId finds a single collection by its name (case insensitive) or id. + * SetHidden implements [Field.SetHidden] interface method. */ - findCollectionByNameOrId(nameOrId: string): (models.Collection) + setHidden(hidden: boolean): void } - interface Dao { + interface URLField { /** - * IsCollectionNameUnique checks that there is no existing collection - * with the provided name (case insensitive!). - * - * Note: case insensitive check because the name is used also as a table name for the records. + * ColumnType implements [Field.ColumnType] interface method. */ - isCollectionNameUnique(name: string, ...excludeIds: string[]): boolean + columnType(app: App): string } - interface Dao { + interface URLField { /** - * FindCollectionReferences returns information for all - * relation schema fields referencing the provided collection. - * - * If the provided collection has reference to itself then it will be - * also included in the result. To exclude it, pass the collection id - * as the excludeId argument. + * PrepareValue implements [Field.PrepareValue] interface method. */ - findCollectionReferences(collection: models.Collection, ...excludeIds: string[]): _TygojaDict + prepareValue(record: Record, raw: any): any } - interface Dao { + interface URLField { /** - * DeleteCollection deletes the provided Collection model. - * This method automatically deletes the related collection records table. - * - * NB! The collection cannot be deleted, if: - * - is system collection (aka. collection.System is true) - * - is referenced as part of a relation field in another collection + * ValidateValue implements [Field.ValidateValue] interface method. */ - deleteCollection(collection: models.Collection): void + validateValue(ctx: context.Context, app: App, record: Record): void } - interface Dao { + interface URLField { /** - * SaveCollection persists the provided Collection model and updates - * its related records table schema. - * - * If collection.IsNew() is true, the method will perform a create, otherwise an update. - * To explicitly mark a collection for update you can use collection.MarkAsNotNew(). + * ValidateSettings implements [Field.ValidateSettings] interface method. */ - saveCollection(collection: models.Collection): void + validateSettings(ctx: context.Context, app: App, collection: Collection): void } - interface Dao { + interface newFieldsList { /** - * ImportCollections imports the provided collections list within a single transaction. - * - * NB1! If deleteMissing is set, all local collections and schema fields, that are not present - * in the imported configuration, WILL BE DELETED (including their related records data). - * - * NB2! This method doesn't perform validations on the imported collections data! - * If you need validations, use [forms.CollectionsImport]. + * NewFieldsList creates a new FieldsList instance with the provided fields. */ - importCollections(importedCollections: Array<(models.Collection | undefined)>, deleteMissing: boolean, afterSync: (txDao: Dao, mappedImported: _TygojaDict, mappedExisting: _TygojaDict) => void): void + (...fields: Field[]): FieldsList } - interface Dao { + /** + * FieldsList defines a Collection slice of fields. + */ + interface FieldsList extends Array{} + interface FieldsList { /** - * ExternalAuthQuery returns a new ExternalAuth select query. + * Clone creates a deep clone of the current list. */ - externalAuthQuery(): (dbx.SelectQuery) + clone(): FieldsList } - interface Dao { + interface FieldsList { /** - * FindAllExternalAuthsByRecord returns all ExternalAuth models - * linked to the provided auth record. + * FieldNames returns a slice with the name of all list fields. */ - findAllExternalAuthsByRecord(authRecord: models.Record): Array<(models.ExternalAuth | undefined)> + fieldNames(): Array } - interface Dao { + interface FieldsList { /** - * FindExternalAuthByRecordAndProvider returns the first available - * ExternalAuth model for the specified record data and provider. + * AsMap returns a map with all registered list field. + * The returned map is indexed with each field name. */ - findExternalAuthByRecordAndProvider(authRecord: models.Record, provider: string): (models.ExternalAuth) + asMap(): _TygojaDict } - interface Dao { + interface FieldsList { /** - * FindFirstExternalAuthByExpr returns the first available - * ExternalAuth model that satisfies the non-nil expression. + * GetById returns a single field by its id. */ - findFirstExternalAuthByExpr(expr: dbx.Expression): (models.ExternalAuth) + getById(fieldId: string): Field } - interface Dao { + interface FieldsList { /** - * SaveExternalAuth upserts the provided ExternalAuth model. + * GetByName returns a single field by its name. */ - saveExternalAuth(model: models.ExternalAuth): void + getByName(fieldName: string): Field } - interface Dao { + interface FieldsList { /** - * DeleteExternalAuth deletes the provided ExternalAuth model. + * RemoveById removes a single field by its id. + * + * This method does nothing if field with the specified id doesn't exist. */ - deleteExternalAuth(model: models.ExternalAuth): void + removeById(fieldId: string): void } - interface Dao { + interface FieldsList { /** - * LogQuery returns a new Log select query. + * RemoveByName removes a single field by its name. + * + * This method does nothing if field with the specified name doesn't exist. */ - logQuery(): (dbx.SelectQuery) + removeByName(fieldName: string): void } - interface Dao { + interface FieldsList { /** - * FindLogById finds a single Log entry by its id. + * Add adds one or more fields to the current list. + * + * By default this method will try to REPLACE existing fields with + * the new ones by their id or by their name if the new field doesn't have an explicit id. + * + * If no matching existing field is found, it will APPEND the field to the end of the list. + * + * In all cases, if any of the new fields don't have an explicit id it will auto generate a default one for them + * (the id value doesn't really matter and it is mostly used as a stable identifier in case of a field rename). */ - findLogById(id: string): (models.Log) + add(...fields: Field[]): void } - interface Dao { + interface FieldsList { /** - * LogsStats returns hourly grouped requests logs statistics. + * AddAt is the same as Add but insert/move the fields at the specific position. + * + * If pos < 0, then this method acts the same as calling Add. + * + * If pos > FieldsList total items, then the specified fields are inserted/moved at the end of the list. */ - logsStats(expr: dbx.Expression): Array<(LogsStatsItem | undefined)> + addAt(pos: number, ...fields: Field[]): void } - interface Dao { + interface FieldsList { /** - * DeleteOldLogs delete all requests that are created before createdBefore. + * AddMarshaledJSON parses the provided raw json data and adds the + * found fields into the current list (following the same rule as the Add method). + * + * The rawJSON argument could be one of: + * ``` + * - serialized array of field objects + * - single field object. + * ``` + * + * Example: + * + * ``` + * l.AddMarshaledJSON([]byte{`{"type":"text", name: "test"}`}) + * l.AddMarshaledJSON([]byte{`[{"type":"text", name: "test1"}, {"type":"text", name: "test2"}]`}) + * ``` */ - deleteOldLogs(createdBefore: time.Time): void + addMarshaledJSON(rawJSON: string|Array): void } - interface Dao { + interface FieldsList { /** - * SaveLog upserts the provided Log model. + * AddMarshaledJSONAt is the same as AddMarshaledJSON but insert/move the fields at the specific position. + * + * If pos < 0, then this method acts the same as calling AddMarshaledJSON. + * + * If pos > FieldsList total items, then the specified fields are inserted/moved at the end of the list. */ - saveLog(log: models.Log): void + addMarshaledJSONAt(pos: number, rawJSON: string|Array): void } - interface Dao { + interface FieldsList { /** - * ParamQuery returns a new Param select query. + * String returns the string representation of the current list. */ - paramQuery(): (dbx.SelectQuery) + string(): string + } + interface onlyFieldType { + type: string + } + type _sAjGBsg = Field + interface fieldWithType extends _sAjGBsg { + type: string } - interface Dao { + interface fieldWithType { + unmarshalJSON(data: string|Array): void + } + interface FieldsList { /** - * FindParamByKey finds the first Param model with the provided key. + * UnmarshalJSON implements [json.Unmarshaler] and + * loads the provided json data into the current FieldsList. */ - findParamByKey(key: string): (models.Param) + unmarshalJSON(data: string|Array): void } - interface Dao { + interface FieldsList { /** - * SaveParam creates or updates a Param model by the provided key-value pair. - * The value argument will be encoded as json string. - * - * If `optEncryptionKey` is provided it will encrypt the value before storing it. + * MarshalJSON implements the [json.Marshaler] interface. */ - saveParam(key: string, value: any, ...optEncryptionKey: string[]): void + marshalJSON(): string|Array } - interface Dao { + interface FieldsList { /** - * DeleteParam deletes the provided Param model. + * Value implements the [driver.Valuer] interface. */ - deleteParam(param: models.Param): void + value(): any } - interface Dao { + interface FieldsList { /** - * RecordQuery returns a new Record select query from a collection model, id or name. - * - * In case a collection id or name is provided and that collection doesn't - * actually exists, the generated query will be created with a cancelled context - * and will fail once an executor (Row(), One(), All(), etc.) is called. + * Scan implements [sql.Scanner] interface to scan the provided value + * into the current FieldsList instance. */ - recordQuery(collectionModelOrIdentifier: any): (dbx.SelectQuery) + scan(value: any): void } - interface Dao { + type _sdlGcEZ = BaseModel + interface Log extends _sdlGcEZ { + created: types.DateTime + data: types.JSONMap + message: string + level: number + } + interface Log { + tableName(): string + } + interface BaseApp { /** - * FindRecordById finds the Record model by its id. + * LogQuery returns a new Log select query. */ - findRecordById(collectionNameOrId: string, recordId: string, ...optFilters: ((q: dbx.SelectQuery) => void)[]): (models.Record) + logQuery(): (dbx.SelectQuery) } - interface Dao { + interface BaseApp { /** - * FindRecordsByIds finds all Record models by the provided ids. - * If no records are found, returns an empty slice. + * FindLogById finds a single Log entry by its id. + */ + findLogById(id: string): (Log) + } + /** + * LogsStatsItem defines the total number of logs for a specific time period. + */ + interface LogsStatsItem { + date: types.DateTime + total: number + } + interface BaseApp { + /** + * LogsStats returns hourly grouped logs statistics. */ - findRecordsByIds(collectionNameOrId: string, recordIds: Array, ...optFilters: ((q: dbx.SelectQuery) => void)[]): Array<(models.Record | undefined)> + logsStats(expr: dbx.Expression): Array<(LogsStatsItem | undefined)> } - interface Dao { + interface BaseApp { /** - * FindRecordsByExpr finds all records by the specified db expression. + * DeleteOldLogs delete all logs that are created before createdBefore. * - * Returns all collection records if no expressions are provided. - * - * Returns an empty slice if no records are found. + * For better performance the logs delete is executed as plain SQL statement, + * aka. no delete model hook events will be fired. + */ + deleteOldLogs(createdBefore: time.Time): void + } + /** + * MFA defines a Record proxy for working with the mfas collection. + */ + type _sSGDnjW = Record + interface MFA extends _sSGDnjW { + } + interface newMFA { + /** + * NewMFA instantiates and returns a new blank *MFA model. * - * Example: + * Example usage: * * ``` - * expr1 := dbx.HashExp{"email": "test@example.com"} - * expr2 := dbx.NewExp("LOWER(username) = {:username}", dbx.Params{"username": "test"}) - * dao.FindRecordsByExpr("example", expr1, expr2) + * mfa := core.NewMFA(app) + * mfa.SetRecordRef(user.Id) + * mfa.SetCollectionRef(user.Collection().Id) + * mfa.SetMethod(core.MFAMethodPassword) + * app.Save(mfa) * ``` */ - findRecordsByExpr(collectionNameOrId: string, ...exprs: dbx.Expression[]): Array<(models.Record | undefined)> + (app: App): (MFA) } - interface Dao { + interface MFA { /** - * FindFirstRecordByData returns the first found record matching - * the provided key-value pair. + * PreValidate implements the [PreValidator] interface and checks + * whether the proxy is properly loaded. */ - findFirstRecordByData(collectionNameOrId: string, key: string, value: any): (models.Record) + preValidate(ctx: context.Context, app: App): void } - interface Dao { + interface MFA { /** - * FindRecordsByFilter returns limit number of records matching the - * provided string filter. - * - * NB! Use the last "params" argument to bind untrusted user variables! - * - * The sort argument is optional and can be empty string OR the same format - * used in the web APIs, eg. "-created,title". - * - * If the limit argument is <= 0, no limit is applied to the query and - * all matching records are returned. - * - * Example: - * - * ``` - * dao.FindRecordsByFilter( - * "posts", - * "title ~ {:title} && visible = {:visible}", - * "-created", - * 10, - * 0, - * dbx.Params{"title": "lorem ipsum", "visible": true} - * ) - * ``` + * ProxyRecord returns the proxied Record model. */ - findRecordsByFilter(collectionNameOrId: string, filter: string, sort: string, limit: number, offset: number, ...params: dbx.Params[]): Array<(models.Record | undefined)> + proxyRecord(): (Record) } - interface Dao { + interface MFA { /** - * FindFirstRecordByFilter returns the first available record matching the provided filter. - * - * NB! Use the last params argument to bind untrusted user variables! - * - * Example: - * - * ``` - * dao.FindFirstRecordByFilter("posts", "slug={:slug} && status='public'", dbx.Params{"slug": "test"}) - * ``` + * SetProxyRecord loads the specified record model into the current proxy. */ - findFirstRecordByFilter(collectionNameOrId: string, filter: string, ...params: dbx.Params[]): (models.Record) + setProxyRecord(record: Record): void } - interface Dao { + interface MFA { /** - * IsRecordValueUnique checks if the provided key-value pair is a unique Record value. - * - * For correctness, if the collection is "auth" and the key is "username", - * the unique check will be case insensitive. - * - * NB! Array values (eg. from multiple select fields) are matched - * as a serialized json strings (eg. `["a","b"]`), so the value uniqueness - * depends on the elements order. Or in other words the following values - * are considered different: `[]string{"a","b"}` and `[]string{"b","a"}` + * CollectionRef returns the "collectionRef" field value. */ - isRecordValueUnique(collectionNameOrId: string, key: string, value: any, ...excludeIds: string[]): boolean + collectionRef(): string } - interface Dao { + interface MFA { /** - * FindAuthRecordByToken finds the auth record associated with the provided JWT. - * - * Returns an error if the JWT is invalid, expired or not associated to an auth collection record. + * SetCollectionRef updates the "collectionRef" record field value. */ - findAuthRecordByToken(token: string, baseTokenKey: string): (models.Record) + setCollectionRef(collectionId: string): void } - interface Dao { + interface MFA { /** - * FindAuthRecordByEmail finds the auth record associated with the provided email. - * - * Returns an error if it is not an auth collection or the record is not found. + * RecordRef returns the "recordRef" record field value. */ - findAuthRecordByEmail(collectionNameOrId: string, email: string): (models.Record) + recordRef(): string } - interface Dao { + interface MFA { /** - * FindAuthRecordByUsername finds the auth record associated with the provided username (case insensitive). - * - * Returns an error if it is not an auth collection or the record is not found. + * SetRecordRef updates the "recordRef" record field value. */ - findAuthRecordByUsername(collectionNameOrId: string, username: string): (models.Record) + setRecordRef(recordId: string): void } - interface Dao { + interface MFA { /** - * SuggestUniqueAuthRecordUsername checks if the provided username is unique - * and return a new "unique" username with appended random numeric part - * (eg. "existingName" -> "existingName583"). - * - * The same username will be returned if the provided string is already unique. + * Method returns the "method" record field value. */ - suggestUniqueAuthRecordUsername(collectionNameOrId: string, baseUsername: string, ...excludeIds: string[]): string + method(): string } - interface Dao { + interface MFA { /** - * CanAccessRecord checks if a record is allowed to be accessed by the - * specified requestInfo and accessRule. - * - * Rule and db checks are ignored in case requestInfo.Admin is set. - * - * The returned error indicate that something unexpected happened during - * the check (eg. invalid rule or db error). - * - * The method always return false on invalid access rule or db error. - * - * Example: - * - * ``` - * requestInfo := apis.RequestInfo(c /* echo.Context *\/) - * record, _ := dao.FindRecordById("example", "RECORD_ID") - * rule := types.Pointer("@request.auth.id != '' || status = 'public'") - * // ... or use one of the record collection's rule, eg. record.Collection().ViewRule - * - * if ok, _ := dao.CanAccessRecord(record, requestInfo, rule); ok { ... } - * ``` + * SetMethod updates the "method" record field value. */ - canAccessRecord(record: models.Record, requestInfo: models.RequestInfo, accessRule: string): boolean + setMethod(method: string): void } - interface Dao { + interface MFA { /** - * SaveRecord persists the provided Record model in the database. - * - * If record.IsNew() is true, the method will perform a create, otherwise an update. - * To explicitly mark a record for update you can use record.MarkAsNotNew(). + * Created returns the "created" record field value. */ - saveRecord(record: models.Record): void + created(): types.DateTime } - interface Dao { + interface MFA { /** - * DeleteRecord deletes the provided Record model. - * - * This method will also cascade the delete operation to all linked - * relational records (delete or unset, depending on the rel settings). - * - * The delete operation may fail if the record is part of a required - * reference in another record (aka. cannot be deleted or unset). + * Updated returns the "updated" record field value. */ - deleteRecord(record: models.Record): void + updated(): types.DateTime } - interface Dao { + interface MFA { /** - * ExpandRecord expands the relations of a single Record model. - * - * If optFetchFunc is not set, then a default function will be used - * that returns all relation records. - * - * Returns a map with the failed expand parameters and their errors. + * HasExpired checks if the mfa is expired, aka. whether it has been + * more than maxElapsed time since its creation. */ - expandRecord(record: models.Record, expands: Array, optFetchFunc: ExpandFetchFunc): _TygojaDict + hasExpired(maxElapsed: time.Duration): boolean } - interface Dao { + interface BaseApp { /** - * ExpandRecords expands the relations of the provided Record models list. - * - * If optFetchFunc is not set, then a default function will be used - * that returns all relation records. - * - * Returns a map with the failed expand parameters and their errors. + * FindAllMFAsByRecord returns all MFA models linked to the provided auth record. */ - expandRecords(records: Array<(models.Record | undefined)>, expands: Array, optFetchFunc: ExpandFetchFunc): _TygojaDict + findAllMFAsByRecord(authRecord: Record): Array<(MFA | undefined)> } - // @ts-ignore - import validation = ozzo_validation - interface Dao { + interface BaseApp { /** - * SyncRecordTableSchema compares the two provided collections - * and applies the necessary related record table changes. - * - * If `oldCollection` is null, then only `newCollection` is used to create the record table. + * FindAllMFAsByCollection returns all MFA models linked to the provided collection. */ - syncRecordTableSchema(newCollection: models.Collection, oldCollection: models.Collection): void + findAllMFAsByCollection(collection: Collection): Array<(MFA | undefined)> } - interface Dao { + interface BaseApp { /** - * FindSettings returns and decode the serialized app settings param value. - * - * The method will first try to decode the param value without decryption. - * If it fails and optEncryptionKey is set, it will try again by first - * decrypting the value and then decode it again. - * - * Returns an error if it fails to decode the stored serialized param value. + * FindMFAById returns a single MFA model by its id. */ - findSettings(...optEncryptionKey: string[]): (settings.Settings) + findMFAById(id: string): (MFA) } - interface Dao { + interface BaseApp { /** - * SaveSettings persists the specified settings configuration. + * DeleteAllMFAsByRecord deletes all MFA models associated with the provided record. * - * If optEncryptionKey is set, then the stored serialized value will be encrypted with it. + * Returns a combined error with the failed deletes. */ - saveSettings(newSettings: settings.Settings, ...optEncryptionKey: string[]): void + deleteAllMFAsByRecord(authRecord: Record): void } - interface Dao { + interface BaseApp { /** - * HasTable checks if a table (or view) with the provided name exists (case insensitive). + * DeleteExpiredMFAs deletes the expired MFAs for all auth collections. */ - hasTable(tableName: string): boolean + deleteExpiredMFAs(): void + } + interface Migration { + up: (txApp: App) => void + down: (txApp: App) => void + file: string + reapplyCondition: (txApp: App, runner: MigrationsRunner, fileName: string) => boolean + } + /** + * MigrationsList defines a list with migration definitions + */ + interface MigrationsList { } - interface Dao { + interface MigrationsList { /** - * TableColumns returns all column names of a single table by its name. + * Item returns a single migration from the list by its index. */ - tableColumns(tableName: string): Array + item(index: number): (Migration) + } + interface MigrationsList { + /** + * Items returns the internal migrations list slice. + */ + items(): Array<(Migration | undefined)> } - interface Dao { + interface MigrationsList { /** - * TableInfo returns the `table_info` pragma result for the specified table. + * Copy copies all provided list migrations into the current one. */ - tableInfo(tableName: string): Array<(models.TableInfoRow | undefined)> + copy(list: MigrationsList): void } - interface Dao { + interface MigrationsList { /** - * TableIndexes returns a name grouped map with all non empty index of the specified table. + * Add adds adds an existing migration definition to the list. * - * Note: This method doesn't return an error on nonexisting table. + * If m.File is not provided, it will try to get the name from its .go file. + * + * The list will be sorted automatically based on the migrations file name. */ - tableIndexes(tableName: string): _TygojaDict + add(m: Migration): void } - interface Dao { + interface MigrationsList { /** - * DeleteTable drops the specified table. + * Register adds new migration definition to the list. * - * This method is a no-op if a table with the provided name doesn't exist. + * If optFilename is not provided, it will try to get the name from its .go file. * - * Be aware that this method is vulnerable to SQL injection and the - * "tableName" argument must come only from trusted input! + * The list will be sorted automatically based on the migrations file name. */ - deleteTable(tableName: string): void + register(up: (txApp: App) => void, down: (txApp: App) => void, ...optFilename: string[]): void + } + /** + * MigrationsRunner defines a simple struct for managing the execution of db migrations. + */ + interface MigrationsRunner { } - interface Dao { + interface newMigrationsRunner { /** - * Vacuum executes VACUUM on the current dao.DB() instance in order to - * reclaim unused db disk space. + * NewMigrationsRunner creates and initializes a new db migrations MigrationsRunner instance. */ - vacuum(): void + (app: App, migrationsList: MigrationsList): (MigrationsRunner) } - interface Dao { + interface MigrationsRunner { /** - * DeleteView drops the specified view name. + * Run interactively executes the current runner with the provided args. * - * This method is a no-op if a view with the provided name doesn't exist. - * - * Be aware that this method is vulnerable to SQL injection and the - * "name" argument must come only from trusted input! + * The following commands are supported: + * - up - applies all migrations + * - down [n] - reverts the last n (default 1) applied migrations + * - history-sync - syncs the migrations table with the runner's migrations list */ - deleteView(name: string): void + run(...args: string[]): void } - interface Dao { + interface MigrationsRunner { /** - * SaveView creates (or updates already existing) persistent SQL view. + * Up executes all unapplied migrations for the provided runner. * - * Be aware that this method is vulnerable to SQL injection and the - * "selectQuery" argument must come only from trusted input! + * On success returns list with the applied migrations file names. */ - saveView(name: string, selectQuery: string): void + up(): Array } - interface Dao { + interface MigrationsRunner { /** - * CreateViewSchema creates a new view schema from the provided select query. + * Down reverts the last `toRevertCount` applied migrations + * (in the order they were applied). * - * There are some caveats: - * - The select query must have an "id" column. - * - Wildcard ("*") columns are not supported to avoid accidentally leaking sensitive data. + * On success returns list with the reverted migrations file names. */ - createViewSchema(selectQuery: string): schema.Schema + down(toRevertCount: number): Array } - interface Dao { + interface MigrationsRunner { /** - * FindRecordByViewFile returns the original models.Record of the - * provided view collection file. + * RemoveMissingAppliedMigrations removes the db entries of all applied migrations + * that are not listed in the runner's migrations list. */ - findRecordByViewFile(viewCollectionNameOrId: string, fileFieldName: string, filename: string): (models.Record) + removeMissingAppliedMigrations(): void } -} - -/** - * Package core is the backbone of PocketBase. - * - * It defines the main PocketBase App interface and its base implementation. - */ -namespace core { /** - * App defines the main PocketBase app interface. + * OTP defines a Record proxy for working with the otps collection. */ - interface App { - [key:string]: any; + type _siLrNWc = Record + interface OTP extends _siLrNWc { + } + interface newOTP { /** - * Deprecated: - * This method may get removed in the near future. - * It is recommended to access the app db instance from app.Dao().DB() or - * if you want more flexibility - app.Dao().ConcurrentDB() and app.Dao().NonconcurrentDB(). + * NewOTP instantiates and returns a new blank *OTP model. + * + * Example usage: * - * DB returns the default app database instance. + * ``` + * otp := core.NewOTP(app) + * otp.SetRecordRef(user.Id) + * otp.SetCollectionRef(user.Collection().Id) + * otp.SetPassword(security.RandomStringWithAlphabet(6, "1234567890")) + * app.Save(otp) + * ``` */ - db(): (dbx.DB) + (app: App): (OTP) + } + interface OTP { /** - * Dao returns the default app Dao instance. - * - * This Dao could operate only on the tables and models - * associated with the default app database. For example, - * trying to access the request logs table will result in error. + * PreValidate implements the [PreValidator] interface and checks + * whether the proxy is properly loaded. */ - dao(): (daos.Dao) + preValidate(ctx: context.Context, app: App): void + } + interface OTP { /** - * Deprecated: - * This method may get removed in the near future. - * It is recommended to access the logs db instance from app.LogsDao().DB() or - * if you want more flexibility - app.LogsDao().ConcurrentDB() and app.LogsDao().NonconcurrentDB(). - * - * LogsDB returns the app logs database instance. + * ProxyRecord returns the proxied Record model. */ - logsDB(): (dbx.DB) + proxyRecord(): (Record) + } + interface OTP { /** - * LogsDao returns the app logs Dao instance. - * - * This Dao could operate only on the tables and models - * associated with the logs database. For example, trying to access - * the users table from LogsDao will result in error. + * SetProxyRecord loads the specified record model into the current proxy. */ - logsDao(): (daos.Dao) + setProxyRecord(record: Record): void + } + interface OTP { /** - * Logger returns the active app logger. + * CollectionRef returns the "collectionRef" field value. */ - logger(): (slog.Logger) + collectionRef(): string + } + interface OTP { /** - * DataDir returns the app data directory path. + * SetCollectionRef updates the "collectionRef" record field value. */ - dataDir(): string + setCollectionRef(collectionId: string): void + } + interface OTP { /** - * EncryptionEnv returns the name of the app secret env key - * (used for settings encryption). + * RecordRef returns the "recordRef" record field value. */ - encryptionEnv(): string + recordRef(): string + } + interface OTP { /** - * IsDev returns whether the app is in dev mode. + * SetRecordRef updates the "recordRef" record field value. */ - isDev(): boolean + setRecordRef(recordId: string): void + } + interface OTP { /** - * Settings returns the loaded app settings. + * SentTo returns the "sentTo" record field value. + * + * It could be any string value (email, phone, message app id, etc.) + * and usually is used as part of the auth flow to update the verified + * user state in case for example the sentTo value matches with the user record email. */ - settings(): (settings.Settings) + sentTo(): string + } + interface OTP { /** - * Deprecated: Use app.Store() instead. + * SetSentTo updates the "sentTo" record field value. */ - cache(): (store.Store) + setSentTo(val: string): void + } + interface OTP { /** - * Store returns the app runtime store. + * Created returns the "created" record field value. */ - store(): (store.Store) + created(): types.DateTime + } + interface OTP { /** - * SubscriptionsBroker returns the app realtime subscriptions broker instance. + * Updated returns the "updated" record field value. */ - subscriptionsBroker(): (subscriptions.Broker) + updated(): types.DateTime + } + interface OTP { /** - * NewMailClient creates and returns a configured app mail client. + * HasExpired checks if the otp is expired, aka. whether it has been + * more than maxElapsed time since its creation. */ - newMailClient(): mailer.Mailer + hasExpired(maxElapsed: time.Duration): boolean + } + interface BaseApp { /** - * NewFilesystem creates and returns a configured filesystem.System instance - * for managing regular app files (eg. collection uploads). - * - * NB! Make sure to call Close() on the returned result - * after you are done working with it. - */ - newFilesystem(): (filesystem.System) - /** - * NewBackupsFilesystem creates and returns a configured filesystem.System instance - * for managing app backups. - * - * NB! Make sure to call Close() on the returned result - * after you are done working with it. - */ - newBackupsFilesystem(): (filesystem.System) - /** - * RefreshSettings reinitializes and reloads the stored application settings. - */ - refreshSettings(): void - /** - * IsBootstrapped checks if the application was initialized - * (aka. whether Bootstrap() was called). - */ - isBootstrapped(): boolean - /** - * Bootstrap takes care for initializing the application - * (open db connections, load settings, etc.). - * - * It will call ResetBootstrapState() if the application was already bootstrapped. + * FindAllOTPsByRecord returns all OTP models linked to the provided auth record. */ - bootstrap(): void - /** - * ResetBootstrapState takes care for releasing initialized app resources - * (eg. closing db connections). - */ - resetBootstrapState(): void + findAllOTPsByRecord(authRecord: Record): Array<(OTP | undefined)> + } + interface BaseApp { /** - * CreateBackup creates a new backup of the current app pb_data directory. - * - * Backups can be stored on S3 if it is configured in app.Settings().Backups. - * - * Please refer to the godoc of the specific CoreApp implementation - * for details on the backup procedures. + * FindAllOTPsByCollection returns all OTP models linked to the provided collection. */ - createBackup(ctx: context.Context, name: string): void + findAllOTPsByCollection(collection: Collection): Array<(OTP | undefined)> + } + interface BaseApp { /** - * RestoreBackup restores the backup with the specified name and restarts - * the current running application process. - * - * The safely perform the restore it is recommended to have free disk space - * for at least 2x the size of the restored pb_data backup. - * - * Please refer to the godoc of the specific CoreApp implementation - * for details on the restore procedures. - * - * NB! This feature is experimental and currently is expected to work only on UNIX based systems. + * FindOTPById returns a single OTP model by its id. */ - restoreBackup(ctx: context.Context, name: string): void + findOTPById(id: string): (OTP) + } + interface BaseApp { /** - * Restart restarts the current running application process. + * DeleteAllOTPsByRecord deletes all OTP models associated with the provided record. * - * Currently it is relying on execve so it is supported only on UNIX based systems. + * Returns a combined error with the failed deletes. */ - restart(): void + deleteAllOTPsByRecord(authRecord: Record): void + } + interface BaseApp { /** - * OnBeforeBootstrap hook is triggered before initializing the main - * application resources (eg. before db open and initial settings load). + * DeleteExpiredOTPs deletes the expired OTPs for all auth collections. */ - onBeforeBootstrap(): (hook.Hook) + deleteExpiredOTPs(): void + } + /** + * RecordFieldResolver defines a custom search resolver struct for + * managing Record model search fields. + * + * Usually used together with `search.Provider`. + * Example: + * + * ``` + * resolver := resolvers.NewRecordFieldResolver( + * app, + * myCollection, + * &models.RequestInfo{...}, + * true, + * ) + * provider := search.NewProvider(resolver) + * ... + * ``` + */ + interface RecordFieldResolver { + } + interface RecordFieldResolver { /** - * OnAfterBootstrap hook is triggered after initializing the main - * application resources (eg. after db open and initial settings load). + * AllowedFields returns a copy of the resolver's allowed fields. */ - onAfterBootstrap(): (hook.Hook) + allowedFields(): Array + } + interface RecordFieldResolver { /** - * OnBeforeServe hook is triggered before serving the internal router (echo), - * allowing you to adjust its options and attach new routes or middlewares. + * SetAllowedFields replaces the resolver's allowed fields with the new ones. */ - onBeforeServe(): (hook.Hook) + setAllowedFields(newAllowedFields: Array): void + } + interface RecordFieldResolver { /** - * OnBeforeApiError hook is triggered right before sending an error API - * response to the client, allowing you to further modify the error data - * or to return a completely different API response. + * AllowHiddenFields returns whether the current resolver allows filtering hidden fields. */ - onBeforeApiError(): (hook.Hook) + allowHiddenFields(): boolean + } + interface RecordFieldResolver { /** - * OnAfterApiError hook is triggered right after sending an error API - * response to the client. - * It could be used to log the final API error in external services. + * SetAllowHiddenFields enables or disables hidden fields filtering. */ - onAfterApiError(): (hook.Hook) + setAllowHiddenFields(allowHiddenFields: boolean): void + } + interface newRecordFieldResolver { /** - * OnTerminate hook is triggered when the app is in the process - * of being terminated (eg. on SIGTERM signal). + * NewRecordFieldResolver creates and initializes a new `RecordFieldResolver`. */ - onTerminate(): (hook.Hook) + (app: App, baseCollection: Collection, requestInfo: RequestInfo, allowHiddenFields: boolean): (RecordFieldResolver) + } + interface RecordFieldResolver { /** - * OnModelBeforeCreate hook is triggered before inserting a new - * model in the DB, allowing you to modify or validate the stored data. + * @todo think of a better a way how to call it automatically after BuildExpr * - * If the optional "tags" list (table names and/or the Collection id for Record models) - * is specified, then all event handlers registered via the created hook - * will be triggered and called only if their event data origin matches the tags. - */ - onModelBeforeCreate(...tags: string[]): (hook.TaggedHook) - /** - * OnModelAfterCreate hook is triggered after successfully - * inserting a new model in the DB. + * UpdateQuery implements `search.FieldResolver` interface. * - * If the optional "tags" list (table names and/or the Collection id for Record models) - * is specified, then all event handlers registered via the created hook - * will be triggered and called only if their event data origin matches the tags. + * Conditionally updates the provided search query based on the + * resolved fields (eg. dynamically joining relations). */ - onModelAfterCreate(...tags: string[]): (hook.TaggedHook) + updateQuery(query: dbx.SelectQuery): void + } + interface RecordFieldResolver { /** - * OnModelBeforeUpdate hook is triggered before updating existing - * model in the DB, allowing you to modify or validate the stored data. + * Resolve implements `search.FieldResolver` interface. * - * If the optional "tags" list (table names and/or the Collection id for Record models) - * is specified, then all event handlers registered via the created hook - * will be triggered and called only if their event data origin matches the tags. - */ - onModelBeforeUpdate(...tags: string[]): (hook.TaggedHook) - /** - * OnModelAfterUpdate hook is triggered after successfully updating - * existing model in the DB. + * Example of some resolvable fieldName formats: * - * If the optional "tags" list (table names and/or the Collection id for Record models) - * is specified, then all event handlers registered via the created hook - * will be triggered and called only if their event data origin matches the tags. + * ``` + * id + * someSelect.each + * project.screen.status + * screen.project_via_prototype.name + * @request.context + * @request.method + * @request.query.filter + * @request.headers.x_token + * @request.auth.someRelation.name + * @request.body.someRelation.name + * @request.body.someField + * @request.body.someSelect:each + * @request.body.someField:isset + * @collection.product.name + * ``` */ - onModelAfterUpdate(...tags: string[]): (hook.TaggedHook) + resolve(fieldName: string): (search.ResolverResult) + } + interface mapExtractor { + [key:string]: any; + asMap(): _TygojaDict + } + /** + * join defines the specification for a single SQL JOIN clause. + */ + interface join { + } + /** + * multiMatchSubquery defines a record multi-match subquery expression. + */ + interface multiMatchSubquery { + } + interface multiMatchSubquery { /** - * OnModelBeforeDelete hook is triggered before deleting an - * existing model from the DB. + * Build converts the expression into a SQL fragment. * - * If the optional "tags" list (table names and/or the Collection id for Record models) - * is specified, then all event handlers registered via the created hook - * will be triggered and called only if their event data origin matches the tags. + * Implements [dbx.Expression] interface. */ - onModelBeforeDelete(...tags: string[]): (hook.TaggedHook) + build(db: dbx.DB, params: dbx.Params): string + } + /** + * replaceWithExpression defines a custom expression that will replace + * a placeholder identifier found in "old" with the result of "new". + */ + interface replaceWithExpression { + } + interface replaceWithExpression { /** - * OnModelAfterDelete hook is triggered after successfully deleting an - * existing model from the DB. + * Build converts the expression into a SQL fragment. * - * If the optional "tags" list (table names and/or the Collection id for Record models) - * is specified, then all event handlers registered via the created hook - * will be triggered and called only if their event data origin matches the tags. - */ - onModelAfterDelete(...tags: string[]): (hook.TaggedHook) - /** - * OnMailerBeforeAdminResetPasswordSend hook is triggered right - * before sending a password reset email to an admin, allowing you - * to inspect and customize the email message that is being sent. + * Implements [dbx.Expression] interface. */ - onMailerBeforeAdminResetPasswordSend(): (hook.Hook) + build(db: dbx.DB, params: dbx.Params): string + } + interface runner { + } + type _sJEPXnm = BaseModel + interface Record extends _sJEPXnm { + } + interface newRecord { /** - * OnMailerAfterAdminResetPasswordSend hook is triggered after - * admin password reset email was successfully sent. + * NewRecord initializes a new empty Record model. */ - onMailerAfterAdminResetPasswordSend(): (hook.Hook) + (collection: Collection): (Record) + } + interface Record { /** - * OnMailerBeforeRecordResetPasswordSend hook is triggered right - * before sending a password reset email to an auth record, allowing - * you to inspect and customize the email message that is being sent. + * Collection returns the Collection model associated with the current Record model. * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * NB! The returned collection is only for read purposes and it shouldn't be modified + * because it could have unintended side-effects on other Record models from the same collection. */ - onMailerBeforeRecordResetPasswordSend(...tags: string[]): (hook.TaggedHook) + collection(): (Collection) + } + interface Record { /** - * OnMailerAfterRecordResetPasswordSend hook is triggered after - * an auth record password reset email was successfully sent. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * TableName returns the table name associated with the current Record model. */ - onMailerAfterRecordResetPasswordSend(...tags: string[]): (hook.TaggedHook) + tableName(): string + } + interface Record { /** - * OnMailerBeforeRecordVerificationSend hook is triggered right - * before sending a verification email to an auth record, allowing - * you to inspect and customize the email message that is being sent. + * PostScan implements the [dbx.PostScanner] interface. * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. - */ - onMailerBeforeRecordVerificationSend(...tags: string[]): (hook.TaggedHook) - /** - * OnMailerAfterRecordVerificationSend hook is triggered after a - * verification email was successfully sent to an auth record. + * It essentially refreshes/updates the current Record original state + * as if the model was fetched from the databases for the first time. * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * Or in other words, it means that m.Original().FieldsData() will have + * the same values as m.Record().FieldsData(). */ - onMailerAfterRecordVerificationSend(...tags: string[]): (hook.TaggedHook) + postScan(): void + } + interface Record { /** - * OnMailerBeforeRecordChangeEmailSend hook is triggered right before - * sending a confirmation new address email to an auth record, allowing - * you to inspect and customize the email message that is being sent. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * HookTags returns the hook tags associated with the current record. */ - onMailerBeforeRecordChangeEmailSend(...tags: string[]): (hook.TaggedHook) + hookTags(): Array + } + interface Record { /** - * OnMailerAfterRecordChangeEmailSend hook is triggered after a - * verification email was successfully sent to an auth record. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * BaseFilesPath returns the storage dir path used by the record. */ - onMailerAfterRecordChangeEmailSend(...tags: string[]): (hook.TaggedHook) + baseFilesPath(): string + } + interface Record { /** - * OnRealtimeConnectRequest hook is triggered right before establishing - * the SSE client connection. + * Original returns a shallow copy of the current record model populated + * with its ORIGINAL db data state (aka. right after PostScan()) + * and everything else reset to the defaults. + * + * If record was created using NewRecord() the original will be always + * a blank record (until PostScan() is invoked). */ - onRealtimeConnectRequest(): (hook.Hook) + original(): (Record) + } + interface Record { /** - * OnRealtimeDisconnectRequest hook is triggered on disconnected/interrupted - * SSE client connection. + * Fresh returns a shallow copy of the current record model populated + * with its LATEST data state and everything else reset to the defaults + * (aka. no expand, no unknown fields and with default visibility flags). */ - onRealtimeDisconnectRequest(): (hook.Hook) + fresh(): (Record) + } + interface Record { /** - * OnRealtimeBeforeMessageSend hook is triggered right before sending - * an SSE message to a client. + * Clone returns a shallow copy of the current record model with all of + * its collection and unknown fields data, expand and flags copied. * - * Returning [hook.StopPropagation] will prevent sending the message. - * Returning any other non-nil error will close the realtime connection. + * use [Record.Fresh()] instead if you want a copy with only the latest + * collection fields data and everything else reset to the defaults. */ - onRealtimeBeforeMessageSend(): (hook.Hook) + clone(): (Record) + } + interface Record { /** - * OnRealtimeAfterMessageSend hook is triggered right after sending - * an SSE message to a client. + * Expand returns a shallow copy of the current Record model expand data (if any). */ - onRealtimeAfterMessageSend(): (hook.Hook) + expand(): _TygojaDict + } + interface Record { /** - * OnRealtimeBeforeSubscribeRequest hook is triggered before changing - * the client subscriptions, allowing you to further validate and - * modify the submitted change. + * SetExpand replaces the current Record's expand with the provided expand arg data (shallow copied). */ - onRealtimeBeforeSubscribeRequest(): (hook.Hook) + setExpand(expand: _TygojaDict): void + } + interface Record { /** - * OnRealtimeAfterSubscribeRequest hook is triggered after the client - * subscriptions were successfully changed. + * MergeExpand merges recursively the provided expand data into + * the current model's expand (if any). + * + * Note that if an expanded prop with the same key is a slice (old or new expand) + * then both old and new records will be merged into a new slice (aka. a :merge: [b,c] => [a,b,c]). + * Otherwise the "old" expanded record will be replace with the "new" one (aka. a :merge: aNew => aNew). */ - onRealtimeAfterSubscribeRequest(): (hook.Hook) + mergeExpand(expand: _TygojaDict): void + } + interface Record { /** - * OnSettingsListRequest hook is triggered on each successful - * API Settings list request. - * - * Could be used to validate or modify the response before - * returning it to the client. + * FieldsData returns a shallow copy ONLY of the collection's fields record's data. */ - onSettingsListRequest(): (hook.Hook) + fieldsData(): _TygojaDict + } + interface Record { /** - * OnSettingsBeforeUpdateRequest hook is triggered before each API - * Settings update request (after request data load and before settings persistence). + * CustomData returns a shallow copy ONLY of the custom record fields data, + * aka. fields that are neither defined by the collection, nor special system ones. * - * Could be used to additionally validate the request data or - * implement completely different persistence behavior. + * Note that custom fields prefixed with "@pbInternal" are always skipped. */ - onSettingsBeforeUpdateRequest(): (hook.Hook) + customData(): _TygojaDict + } + interface Record { /** - * OnSettingsAfterUpdateRequest hook is triggered after each - * successful API Settings update request. + * WithCustomData toggles the export/serialization of custom data fields + * (false by default). */ - onSettingsAfterUpdateRequest(): (hook.Hook) + withCustomData(state: boolean): (Record) + } + interface Record { /** - * OnFileDownloadRequest hook is triggered before each API File download request. - * - * Could be used to validate or modify the file response before - * returning it to the client. + * IgnoreEmailVisibility toggles the flag to ignore the auth record email visibility check. */ - onFileDownloadRequest(...tags: string[]): (hook.TaggedHook) + ignoreEmailVisibility(state: boolean): (Record) + } + interface Record { /** - * OnFileBeforeTokenRequest hook is triggered before each file - * token API request. + * IgnoreUnchangedFields toggles the flag to ignore the unchanged fields + * from the DB export for the UPDATE SQL query. * - * If no token or model was submitted, e.Model and e.Token will be empty, - * allowing you to implement your own custom model file auth implementation. + * This could be used if you want to save only the record fields that you've changed + * without overwrite other untouched fields in case of concurrent update. * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * Note that the fields change comparison is based on the current fields against m.Original() + * (aka. if you have performed save on the same Record instance multiple times you may have to refetch it, + * so that m.Original() could reflect the last saved change). */ - onFileBeforeTokenRequest(...tags: string[]): (hook.TaggedHook) + ignoreUnchangedFields(state: boolean): (Record) + } + interface Record { /** - * OnFileAfterTokenRequest hook is triggered after each - * successful file token API request. + * Set sets the provided key-value data pair into the current Record + * model directly as it is WITHOUT NORMALIZATIONS. * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * See also [Record.Set]. */ - onFileAfterTokenRequest(...tags: string[]): (hook.TaggedHook) + setRaw(key: string, value: any): void + } + interface Record { /** - * OnAdminsListRequest hook is triggered on each API Admins list request. + * SetIfFieldExists sets the provided key-value data pair into the current Record model + * ONLY if key is existing Collection field name/modifier. * - * Could be used to validate or modify the response before returning it to the client. - */ - onAdminsListRequest(): (hook.Hook) - /** - * OnAdminViewRequest hook is triggered on each API Admin view request. + * This method does nothing if key is not a known Collection field name/modifier. * - * Could be used to validate or modify the response before returning it to the client. - */ - onAdminViewRequest(): (hook.Hook) - /** - * OnAdminBeforeCreateRequest hook is triggered before each API - * Admin create request (after request data load and before model persistence). + * On success returns the matched Field, otherwise - nil. * - * Could be used to additionally validate the request data or implement - * completely different persistence behavior. + * To set any key-value, including custom/unknown fields, use the [Record.Set] method. */ - onAdminBeforeCreateRequest(): (hook.Hook) + setIfFieldExists(key: string, value: any): Field + } + interface Record { /** - * OnAdminAfterCreateRequest hook is triggered after each - * successful API Admin create request. + * Set sets the provided key-value data pair into the current Record model. + * + * If the record collection has field with name matching the provided "key", + * the value will be further normalized according to the field setter(s). */ - onAdminAfterCreateRequest(): (hook.Hook) + set(key: string, value: any): void + } + interface Record { + getRaw(key: string): any + } + interface Record { /** - * OnAdminBeforeUpdateRequest hook is triggered before each API - * Admin update request (after request data load and before model persistence). - * - * Could be used to additionally validate the request data or implement - * completely different persistence behavior. + * Get returns a normalized single record model data value for "key". */ - onAdminBeforeUpdateRequest(): (hook.Hook) + get(key: string): any + } + interface Record { /** - * OnAdminAfterUpdateRequest hook is triggered after each - * successful API Admin update request. + * Load bulk loads the provided data into the current Record model. */ - onAdminAfterUpdateRequest(): (hook.Hook) + load(data: _TygojaDict): void + } + interface Record { /** - * OnAdminBeforeDeleteRequest hook is triggered before each API - * Admin delete request (after model load and before actual deletion). - * - * Could be used to additionally validate the request data or implement - * completely different delete behavior. + * GetBool returns the data value for "key" as a bool. */ - onAdminBeforeDeleteRequest(): (hook.Hook) + getBool(key: string): boolean + } + interface Record { /** - * OnAdminAfterDeleteRequest hook is triggered after each - * successful API Admin delete request. + * GetString returns the data value for "key" as a string. */ - onAdminAfterDeleteRequest(): (hook.Hook) + getString(key: string): string + } + interface Record { /** - * OnAdminAuthRequest hook is triggered on each successful API Admin - * authentication request (sign-in, token refresh, etc.). - * - * Could be used to additionally validate or modify the - * authenticated admin data and token. + * GetInt returns the data value for "key" as an int. */ - onAdminAuthRequest(): (hook.Hook) + getInt(key: string): number + } + interface Record { /** - * OnAdminBeforeAuthWithPasswordRequest hook is triggered before each Admin - * auth with password API request (after request data load and before password validation). - * - * Could be used to implement for example a custom password validation - * or to locate a different Admin identity (by assigning [AdminAuthWithPasswordEvent.Admin]). + * GetFloat returns the data value for "key" as a float64. */ - onAdminBeforeAuthWithPasswordRequest(): (hook.Hook) + getFloat(key: string): number + } + interface Record { /** - * OnAdminAfterAuthWithPasswordRequest hook is triggered after each - * successful Admin auth with password API request. + * GetDateTime returns the data value for "key" as a DateTime instance. */ - onAdminAfterAuthWithPasswordRequest(): (hook.Hook) + getDateTime(key: string): types.DateTime + } + interface Record { /** - * OnAdminBeforeAuthRefreshRequest hook is triggered before each Admin - * auth refresh API request (right before generating a new auth token). - * - * Could be used to additionally validate the request data or implement - * completely different auth refresh behavior. + * GetGeoPoint returns the data value for "key" as a GeoPoint instance. */ - onAdminBeforeAuthRefreshRequest(): (hook.Hook) + getGeoPoint(key: string): types.GeoPoint + } + interface Record { /** - * OnAdminAfterAuthRefreshRequest hook is triggered after each - * successful auth refresh API request (right after generating a new auth token). + * GetStringSlice returns the data value for "key" as a slice of non-zero unique strings. */ - onAdminAfterAuthRefreshRequest(): (hook.Hook) + getStringSlice(key: string): Array + } + interface Record { /** - * OnAdminBeforeRequestPasswordResetRequest hook is triggered before each Admin - * request password reset API request (after request data load and before sending the reset email). + * GetUnsavedFiles returns the uploaded files for the provided "file" field key, + * (aka. the current [*filesytem.File] values) so that you can apply further + * validations or modifications (including changing the file name or content before persisting). * - * Could be used to additionally validate the request data or implement - * completely different password reset behavior. + * Example: + * + * ``` + * files := record.GetUnsavedFiles("documents") + * for _, f := range files { + * f.Name = "doc_" + f.Name // add a prefix to each file name + * } + * app.Save(record) // the files are pointers so the applied changes will transparently reflect on the record value + * ``` */ - onAdminBeforeRequestPasswordResetRequest(): (hook.Hook) + getUnsavedFiles(key: string): Array<(filesystem.File | undefined)> + } + interface Record { /** - * OnAdminAfterRequestPasswordResetRequest hook is triggered after each - * successful request password reset API request. + * Deprecated: replaced with GetUnsavedFiles. */ - onAdminAfterRequestPasswordResetRequest(): (hook.Hook) + getUploadedFiles(key: string): Array<(filesystem.File | undefined)> + } + interface Record { /** - * OnAdminBeforeConfirmPasswordResetRequest hook is triggered before each Admin - * confirm password reset API request (after request data load and before persistence). + * Retrieves the "key" json field value and unmarshals it into "result". * - * Could be used to additionally validate the request data or implement - * completely different persistence behavior. - */ - onAdminBeforeConfirmPasswordResetRequest(): (hook.Hook) - /** - * OnAdminAfterConfirmPasswordResetRequest hook is triggered after each - * successful confirm password reset API request. + * Example + * + * ``` + * result := struct { + * FirstName string `json:"first_name"` + * }{} + * err := m.UnmarshalJSONField("my_field_name", &result) + * ``` */ - onAdminAfterConfirmPasswordResetRequest(): (hook.Hook) + unmarshalJSONField(key: string, result: any): void + } + interface Record { /** - * OnRecordAuthRequest hook is triggered on each successful API - * record authentication request (sign-in, token refresh, etc.). + * ExpandedOne retrieves a single relation Record from the already + * loaded expand data of the current model. * - * Could be used to additionally validate or modify the authenticated - * record data and token. + * If the requested expand relation is multiple, this method returns + * only first available Record from the expanded relation. * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * Returns nil if there is no such expand relation loaded. */ - onRecordAuthRequest(...tags: string[]): (hook.TaggedHook) + expandedOne(relField: string): (Record) + } + interface Record { /** - * OnRecordBeforeAuthWithPasswordRequest hook is triggered before each Record - * auth with password API request (after request data load and before password validation). + * ExpandedAll retrieves a slice of relation Records from the already + * loaded expand data of the current model. * - * Could be used to implement for example a custom password validation - * or to locate a different Record model (by reassigning [RecordAuthWithPasswordEvent.Record]). + * If the requested expand relation is single, this method normalizes + * the return result and will wrap the single model as a slice. * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * Returns nil slice if there is no such expand relation loaded. */ - onRecordBeforeAuthWithPasswordRequest(...tags: string[]): (hook.TaggedHook) + expandedAll(relField: string): Array<(Record | undefined)> + } + interface Record { /** - * OnRecordAfterAuthWithPasswordRequest hook is triggered after each - * successful Record auth with password API request. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * FindFileFieldByFile returns the first file type field for which + * any of the record's data contains the provided filename. */ - onRecordAfterAuthWithPasswordRequest(...tags: string[]): (hook.TaggedHook) + findFileFieldByFile(filename: string): (FileField) + } + interface Record { /** - * OnRecordBeforeAuthWithOAuth2Request hook is triggered before each Record - * OAuth2 sign-in/sign-up API request (after token exchange and before external provider linking). - * - * If the [RecordAuthWithOAuth2Event.Record] is not set, then the OAuth2 - * request will try to create a new auth Record. - * - * To assign or link a different existing record model you can - * change the [RecordAuthWithOAuth2Event.Record] field. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * DBExport implements the [DBExporter] interface and returns a key-value + * map with the data to be persisted when saving the Record in the database. */ - onRecordBeforeAuthWithOAuth2Request(...tags: string[]): (hook.TaggedHook) + dbExport(app: App): _TygojaDict + } + interface Record { /** - * OnRecordAfterAuthWithOAuth2Request hook is triggered after each - * successful Record OAuth2 API request. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * Hide hides the specified fields from the public safe serialization of the record. */ - onRecordAfterAuthWithOAuth2Request(...tags: string[]): (hook.TaggedHook) + hide(...fieldNames: string[]): (Record) + } + interface Record { /** - * OnRecordBeforeAuthRefreshRequest hook is triggered before each Record - * auth refresh API request (right before generating a new auth token). + * Unhide forces to unhide the specified fields from the public safe serialization + * of the record (even when the collection field itself is marked as hidden). + */ + unhide(...fieldNames: string[]): (Record) + } + interface Record { + /** + * PublicExport exports only the record fields that are safe to be public. * - * Could be used to additionally validate the request data or implement - * completely different auth refresh behavior. + * To export unknown data fields you need to set record.WithCustomData(true). * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * For auth records, to force the export of the email field you need to set + * record.IgnoreEmailVisibility(true). */ - onRecordBeforeAuthRefreshRequest(...tags: string[]): (hook.TaggedHook) + publicExport(): _TygojaDict + } + interface Record { /** - * OnRecordAfterAuthRefreshRequest hook is triggered after each - * successful auth refresh API request (right after generating a new auth token). + * MarshalJSON implements the [json.Marshaler] interface. * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * Only the data exported by `PublicExport()` will be serialized. */ - onRecordAfterAuthRefreshRequest(...tags: string[]): (hook.TaggedHook) + marshalJSON(): string|Array + } + interface Record { /** - * OnRecordListExternalAuthsRequest hook is triggered on each API record external auths list request. - * - * Could be used to validate or modify the response before returning it to the client. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * UnmarshalJSON implements the [json.Unmarshaler] interface. */ - onRecordListExternalAuthsRequest(...tags: string[]): (hook.TaggedHook) + unmarshalJSON(data: string|Array): void + } + interface Record { /** - * OnRecordBeforeUnlinkExternalAuthRequest hook is triggered before each API record - * external auth unlink request (after models load and before the actual relation deletion). + * ReplaceModifiers returns a new map with applied modifier + * values based on the current record and the specified data. * - * Could be used to additionally validate the request data or implement - * completely different delete behavior. + * The resolved modifier keys will be removed. * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * Multiple modifiers will be applied one after another, + * while reusing the previous base key value result (ex. 1; -5; +2 => -2). + * + * Note that because Go doesn't guaranteed the iteration order of maps, + * we would explicitly apply shorter keys first for a more consistent and reproducible behavior. + * + * Example usage: + * + * ``` + * newData := record.ReplaceModifiers(data) + * // record: {"field": 10} + * // data: {"field+": 5} + * // result: {"field": 15} + * ``` */ - onRecordBeforeUnlinkExternalAuthRequest(...tags: string[]): (hook.TaggedHook) + replaceModifiers(data: _TygojaDict): _TygojaDict + } + interface Record { /** - * OnRecordAfterUnlinkExternalAuthRequest hook is triggered after each - * successful API record external auth unlink request. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * Email returns the "email" record field value (usually available with Auth collections). */ - onRecordAfterUnlinkExternalAuthRequest(...tags: string[]): (hook.TaggedHook) + email(): string + } + interface Record { /** - * OnRecordBeforeRequestPasswordResetRequest hook is triggered before each Record - * request password reset API request (after request data load and before sending the reset email). - * - * Could be used to additionally validate the request data or implement - * completely different password reset behavior. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * SetEmail sets the "email" record field value (usually available with Auth collections). */ - onRecordBeforeRequestPasswordResetRequest(...tags: string[]): (hook.TaggedHook) + setEmail(email: string): void + } + interface Record { /** - * OnRecordAfterRequestPasswordResetRequest hook is triggered after each - * successful request password reset API request. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * Verified returns the "emailVisibility" record field value (usually available with Auth collections). */ - onRecordAfterRequestPasswordResetRequest(...tags: string[]): (hook.TaggedHook) + emailVisibility(): boolean + } + interface Record { /** - * OnRecordBeforeConfirmPasswordResetRequest hook is triggered before each Record - * confirm password reset API request (after request data load and before persistence). - * - * Could be used to additionally validate the request data or implement - * completely different persistence behavior. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * SetEmailVisibility sets the "emailVisibility" record field value (usually available with Auth collections). */ - onRecordBeforeConfirmPasswordResetRequest(...tags: string[]): (hook.TaggedHook) + setEmailVisibility(visible: boolean): void + } + interface Record { /** - * OnRecordAfterConfirmPasswordResetRequest hook is triggered after each - * successful confirm password reset API request. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * Verified returns the "verified" record field value (usually available with Auth collections). */ - onRecordAfterConfirmPasswordResetRequest(...tags: string[]): (hook.TaggedHook) + verified(): boolean + } + interface Record { /** - * OnRecordBeforeRequestVerificationRequest hook is triggered before each Record - * request verification API request (after request data load and before sending the verification email). - * - * Could be used to additionally validate the loaded request data or implement - * completely different verification behavior. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * SetVerified sets the "verified" record field value (usually available with Auth collections). */ - onRecordBeforeRequestVerificationRequest(...tags: string[]): (hook.TaggedHook) + setVerified(verified: boolean): void + } + interface Record { /** - * OnRecordAfterRequestVerificationRequest hook is triggered after each - * successful request verification API request. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * TokenKey returns the "tokenKey" record field value (usually available with Auth collections). */ - onRecordAfterRequestVerificationRequest(...tags: string[]): (hook.TaggedHook) + tokenKey(): string + } + interface Record { /** - * OnRecordBeforeConfirmVerificationRequest hook is triggered before each Record - * confirm verification API request (after request data load and before persistence). - * - * Could be used to additionally validate the request data or implement - * completely different persistence behavior. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * SetTokenKey sets the "tokenKey" record field value (usually available with Auth collections). */ - onRecordBeforeConfirmVerificationRequest(...tags: string[]): (hook.TaggedHook) + setTokenKey(key: string): void + } + interface Record { /** - * OnRecordAfterConfirmVerificationRequest hook is triggered after each - * successful confirm verification API request. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * RefreshTokenKey generates and sets a new random auth record "tokenKey". */ - onRecordAfterConfirmVerificationRequest(...tags: string[]): (hook.TaggedHook) + refreshTokenKey(): void + } + interface Record { /** - * OnRecordBeforeRequestEmailChangeRequest hook is triggered before each Record request email change API request - * (after request data load and before sending the email link to confirm the change). - * - * Could be used to additionally validate the request data or implement - * completely different request email change behavior. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * SetPassword sets the "password" record field value (usually available with Auth collections). */ - onRecordBeforeRequestEmailChangeRequest(...tags: string[]): (hook.TaggedHook) + setPassword(password: string): void + } + interface Record { /** - * OnRecordAfterRequestEmailChangeRequest hook is triggered after each - * successful request email change API request. + * SetRandomPassword sets the "password" auth record field to a random autogenerated value. * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * The autogenerated password is ~30 characters and it is set directly as hash, + * aka. the field plain password value validators (length, pattern, etc.) are ignored + * (this is usually used as part of the auto created OTP or OAuth2 user flows). */ - onRecordAfterRequestEmailChangeRequest(...tags: string[]): (hook.TaggedHook) + setRandomPassword(): string + } + interface Record { /** - * OnRecordBeforeConfirmEmailChangeRequest hook is triggered before each Record - * confirm email change API request (after request data load and before persistence). - * - * Could be used to additionally validate the request data or implement - * completely different persistence behavior. + * ValidatePassword validates a plain password against the "password" record field. * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * Returns false if the password is incorrect. */ - onRecordBeforeConfirmEmailChangeRequest(...tags: string[]): (hook.TaggedHook) + validatePassword(password: string): boolean + } + interface Record { /** - * OnRecordAfterConfirmEmailChangeRequest hook is triggered after each - * successful confirm email change API request. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * IsSuperuser returns whether the current record is a superuser, aka. + * whether the record is from the _superusers collection. */ - onRecordAfterConfirmEmailChangeRequest(...tags: string[]): (hook.TaggedHook) + isSuperuser(): boolean + } + /** + * RecordProxy defines an interface for a Record proxy/project model, + * aka. custom model struct that acts on behalve the proxied Record to + * allow for example typed getter/setters for the Record fields. + * + * To implement the interface it is usually enough to embed the [BaseRecordProxy] struct. + */ + interface RecordProxy { + [key:string]: any; /** - * OnRecordsListRequest hook is triggered on each API Records list request. - * - * Could be used to validate or modify the response before returning it to the client. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * ProxyRecord returns the proxied Record model. */ - onRecordsListRequest(...tags: string[]): (hook.TaggedHook) + proxyRecord(): (Record) /** - * OnRecordViewRequest hook is triggered on each API Record view request. - * - * Could be used to validate or modify the response before returning it to the client. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * SetProxyRecord loads the specified record model into the current proxy. */ - onRecordViewRequest(...tags: string[]): (hook.TaggedHook) + setProxyRecord(record: Record): void + } + /** + * BaseRecordProxy implements the [RecordProxy] interface and it is intended + * to be used as embed to custom user provided Record proxy structs. + */ + type _sqBPuFh = Record + interface BaseRecordProxy extends _sqBPuFh { + } + interface BaseRecordProxy { /** - * OnRecordBeforeCreateRequest hook is triggered before each API Record - * create request (after request data load and before model persistence). - * - * Could be used to additionally validate the request data or implement - * completely different persistence behavior. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * ProxyRecord returns the proxied Record model. */ - onRecordBeforeCreateRequest(...tags: string[]): (hook.TaggedHook) + proxyRecord(): (Record) + } + interface BaseRecordProxy { /** - * OnRecordAfterCreateRequest hook is triggered after each - * successful API Record create request. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * SetProxyRecord loads the specified record model into the current proxy. */ - onRecordAfterCreateRequest(...tags: string[]): (hook.TaggedHook) + setProxyRecord(record: Record): void + } + interface BaseApp { /** - * OnRecordBeforeUpdateRequest hook is triggered before each API Record - * update request (after request data load and before model persistence). + * RecordQuery returns a new Record select query from a collection model, id or name. * - * Could be used to additionally validate the request data or implement - * completely different persistence behavior. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * In case a collection id or name is provided and that collection doesn't + * actually exists, the generated query will be created with a cancelled context + * and will fail once an executor (Row(), One(), All(), etc.) is called. */ - onRecordBeforeUpdateRequest(...tags: string[]): (hook.TaggedHook) + recordQuery(collectionModelOrIdentifier: any): (dbx.SelectQuery) + } + interface BaseApp { /** - * OnRecordAfterUpdateRequest hook is triggered after each - * successful API Record update request. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * FindRecordById finds the Record model by its id. */ - onRecordAfterUpdateRequest(...tags: string[]): (hook.TaggedHook) + findRecordById(collectionModelOrIdentifier: any, recordId: string, ...optFilters: ((q: dbx.SelectQuery) => void)[]): (Record) + } + interface BaseApp { /** - * OnRecordBeforeDeleteRequest hook is triggered before each API Record - * delete request (after model load and before actual deletion). - * - * Could be used to additionally validate the request data or implement - * completely different delete behavior. - * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. + * FindRecordsByIds finds all records by the specified ids. + * If no records are found, returns an empty slice. */ - onRecordBeforeDeleteRequest(...tags: string[]): (hook.TaggedHook) + findRecordsByIds(collectionModelOrIdentifier: any, recordIds: Array, ...optFilters: ((q: dbx.SelectQuery) => void)[]): Array<(Record | undefined)> + } + interface BaseApp { /** - * OnRecordAfterDeleteRequest hook is triggered after each - * successful API Record delete request. + * FindAllRecords finds all records matching specified db expressions. * - * If the optional "tags" list (Collection ids or names) is specified, - * then all event handlers registered via the created hook will be - * triggered and called only if their event data origin matches the tags. - */ - onRecordAfterDeleteRequest(...tags: string[]): (hook.TaggedHook) - /** - * OnCollectionsListRequest hook is triggered on each API Collections list request. + * Returns all collection records if no expression is provided. * - * Could be used to validate or modify the response before returning it to the client. - */ - onCollectionsListRequest(): (hook.Hook) - /** - * OnCollectionViewRequest hook is triggered on each API Collection view request. + * Returns an empty slice if no records are found. * - * Could be used to validate or modify the response before returning it to the client. - */ - onCollectionViewRequest(): (hook.Hook) - /** - * OnCollectionBeforeCreateRequest hook is triggered before each API Collection - * create request (after request data load and before model persistence). + * Example: * - * Could be used to additionally validate the request data or implement - * completely different persistence behavior. + * ``` + * // no extra expressions + * app.FindAllRecords("example") + * + * // with extra expressions + * expr1 := dbx.HashExp{"email": "test@example.com"} + * expr2 := dbx.NewExp("LOWER(username) = {:username}", dbx.Params{"username": "test"}) + * app.FindAllRecords("example", expr1, expr2) + * ``` */ - onCollectionBeforeCreateRequest(): (hook.Hook) + findAllRecords(collectionModelOrIdentifier: any, ...exprs: dbx.Expression[]): Array<(Record | undefined)> + } + interface BaseApp { /** - * OnCollectionAfterCreateRequest hook is triggered after each - * successful API Collection create request. + * FindFirstRecordByData returns the first found record matching + * the provided key-value pair. */ - onCollectionAfterCreateRequest(): (hook.Hook) + findFirstRecordByData(collectionModelOrIdentifier: any, key: string, value: any): (Record) + } + interface BaseApp { /** - * OnCollectionBeforeUpdateRequest hook is triggered before each API Collection - * update request (after request data load and before model persistence). + * FindRecordsByFilter returns limit number of records matching the + * provided string filter. * - * Could be used to additionally validate the request data or implement - * completely different persistence behavior. + * NB! Use the last "params" argument to bind untrusted user variables! + * + * The filter argument is optional and can be empty string to target + * all available records. + * + * The sort argument is optional and can be empty string OR the same format + * used in the web APIs, ex. "-created,title". + * + * If the limit argument is <= 0, no limit is applied to the query and + * all matching records are returned. + * + * Returns an empty slice if no records are found. + * + * Example: + * + * ``` + * app.FindRecordsByFilter( + * "posts", + * "title ~ {:title} && visible = {:visible}", + * "-created", + * 10, + * 0, + * dbx.Params{"title": "lorem ipsum", "visible": true} + * ) + * ``` */ - onCollectionBeforeUpdateRequest(): (hook.Hook) + findRecordsByFilter(collectionModelOrIdentifier: any, filter: string, sort: string, limit: number, offset: number, ...params: dbx.Params[]): Array<(Record | undefined)> + } + interface BaseApp { /** - * OnCollectionAfterUpdateRequest hook is triggered after each - * successful API Collection update request. + * FindFirstRecordByFilter returns the first available record matching the provided filter (if any). + * + * NB! Use the last params argument to bind untrusted user variables! + * + * Returns sql.ErrNoRows if no record is found. + * + * Example: + * + * ``` + * app.FindFirstRecordByFilter("posts", "") + * app.FindFirstRecordByFilter("posts", "slug={:slug} && status='public'", dbx.Params{"slug": "test"}) + * ``` */ - onCollectionAfterUpdateRequest(): (hook.Hook) + findFirstRecordByFilter(collectionModelOrIdentifier: any, filter: string, ...params: dbx.Params[]): (Record) + } + interface BaseApp { /** - * OnCollectionBeforeDeleteRequest hook is triggered before each API - * Collection delete request (after model load and before actual deletion). - * - * Could be used to additionally validate the request data or implement - * completely different delete behavior. + * CountRecords returns the total number of records in a collection. */ - onCollectionBeforeDeleteRequest(): (hook.Hook) + countRecords(collectionModelOrIdentifier: any, ...exprs: dbx.Expression[]): number + } + interface BaseApp { /** - * OnCollectionAfterDeleteRequest hook is triggered after each - * successful API Collection delete request. + * FindAuthRecordByToken finds the auth record associated with the provided JWT + * (auth, file, verifyEmail, changeEmail, passwordReset types). + * + * Optionally specify a list of validTypes to check tokens only from those types. + * + * Returns an error if the JWT is invalid, expired or not associated to an auth collection record. */ - onCollectionAfterDeleteRequest(): (hook.Hook) + findAuthRecordByToken(token: string, ...validTypes: string[]): (Record) + } + interface BaseApp { /** - * OnCollectionsBeforeImportRequest hook is triggered before each API - * collections import request (after request data load and before the actual import). + * FindAuthRecordByEmail finds the auth record associated with the provided email. * - * Could be used to additionally validate the imported collections or - * to implement completely different import behavior. + * The email check would be case-insensitive if the related collection + * email unique index has COLLATE NOCASE specified for the email column. + * + * Returns an error if it is not an auth collection or the record is not found. */ - onCollectionsBeforeImportRequest(): (hook.Hook) + findAuthRecordByEmail(collectionModelOrIdentifier: any, email: string): (Record) + } + interface BaseApp { /** - * OnCollectionsAfterImportRequest hook is triggered after each - * successful API collections import request. + * CanAccessRecord checks if a record is allowed to be accessed by the + * specified requestInfo and accessRule. + * + * Rule and db checks are ignored in case requestInfo.Auth is a superuser. + * + * The returned error indicate that something unexpected happened during + * the check (eg. invalid rule or db query error). + * + * The method always return false on invalid rule or db query error. + * + * Example: + * + * ``` + * requestInfo, _ := e.RequestInfo() + * record, _ := app.FindRecordById("example", "RECORD_ID") + * rule := types.Pointer("@request.auth.id != '' || status = 'public'") + * // ... or use one of the record collection's rule, eg. record.Collection().ViewRule + * + * if ok, _ := app.CanAccessRecord(record, requestInfo, rule); ok { ... } + * ``` */ - onCollectionsAfterImportRequest(): (hook.Hook) + canAccessRecord(record: Record, requestInfo: RequestInfo, accessRule: string): boolean } -} - -namespace migrate { /** - * MigrationsList defines a list with migration definitions + * ExpandFetchFunc defines the function that is used to fetch the expanded relation records. */ - interface MigrationsList { - } - interface MigrationsList { + interface ExpandFetchFunc {(relCollection: Collection, relIds: Array): Array<(Record | undefined)> } + interface BaseApp { /** - * Item returns a single migration from the list by its index. + * ExpandRecord expands the relations of a single Record model. + * + * If optFetchFunc is not set, then a default function will be used + * that returns all relation records. + * + * Returns a map with the failed expand parameters and their errors. */ - item(index: number): (Migration) + expandRecord(record: Record, expands: Array, optFetchFunc: ExpandFetchFunc): _TygojaDict } - interface MigrationsList { + interface BaseApp { /** - * Items returns the internal migrations list slice. + * ExpandRecords expands the relations of the provided Record models list. + * + * If optFetchFunc is not set, then a default function will be used + * that returns all relation records. + * + * Returns a map with the failed expand parameters and their errors. */ - items(): Array<(Migration | undefined)> + expandRecords(records: Array<(Record | undefined)>, expands: Array, optFetchFunc: ExpandFetchFunc): _TygojaDict } - interface MigrationsList { + interface Record { /** - * Register adds new migration definition to the list. + * NewStaticAuthToken generates and returns a new static record authentication token. * - * If `optFilename` is not provided, it will try to get the name from its .go file. + * Static auth tokens are similar to the regular auth tokens, but are + * non-refreshable and support custom duration. * - * The list will be sorted automatically based on the migrations file name. + * Zero or negative duration will fallback to the duration from the auth collection settings. */ - register(up: (db: dbx.Builder) => void, down: (db: dbx.Builder) => void, ...optFilename: string[]): void + newStaticAuthToken(duration: time.Duration): string } -} - -/** - * Package cobra is a commander providing a simple interface to create powerful modern CLI interfaces. - * In addition to providing an interface, Cobra simultaneously provides a controller to organize your application code. - */ -namespace cobra { - interface Command { + interface Record { /** - * GenBashCompletion generates bash completion file and writes to the passed writer. + * NewAuthToken generates and returns a new record authentication token. */ - genBashCompletion(w: io.Writer): void + newAuthToken(): string } - interface Command { + interface Record { /** - * GenBashCompletionFile generates bash completion file. + * NewVerificationToken generates and returns a new record verification token. */ - genBashCompletionFile(filename: string): void + newVerificationToken(): string } - interface Command { + interface Record { /** - * GenBashCompletionFileV2 generates Bash completion version 2. + * NewPasswordResetToken generates and returns a new auth record password reset request token. */ - genBashCompletionFileV2(filename: string, includeDesc: boolean): void + newPasswordResetToken(): string } - interface Command { + interface Record { /** - * GenBashCompletionV2 generates Bash completion file version 2 - * and writes it to the passed writer. + * NewEmailChangeToken generates and returns a new auth record change email request token. */ - genBashCompletionV2(w: io.Writer, includeDesc: boolean): void + newEmailChangeToken(newEmail: string): string + } + interface Record { + /** + * NewFileToken generates and returns a new record private file access token. + */ + newFileToken(): string + } + interface settings { + smtp: SMTPConfig + backups: BackupsConfig + s3: S3Config + meta: MetaConfig + rateLimits: RateLimitsConfig + trustedProxy: TrustedProxyConfig + batch: BatchConfig + logs: LogsConfig } - // @ts-ignore - import flag = pflag /** - * Command is just that, a command for your application. - * E.g. 'go run ...' - 'run' is the command. Cobra requires - * you to define the usage and description as part of your command - * definition to ensure usability. + * Settings defines the PocketBase app settings. */ - interface Command { + type _sgWvOCJ = settings + interface Settings extends _sgWvOCJ { + } + interface Settings { /** - * Use is the one-line usage message. - * Recommended syntax is as follows: - * ``` - * [ ] identifies an optional argument. Arguments that are not enclosed in brackets are required. - * ... indicates that you can specify multiple values for the previous argument. - * | indicates mutually exclusive information. You can use the argument to the left of the separator or the - * argument to the right of the separator. You cannot use both arguments in a single use of the command. - * { } delimits a set of mutually exclusive arguments when one of the arguments is required. If the arguments are - * optional, they are enclosed in brackets ([ ]). - * ``` - * Example: add [-F file | -D dir]... [-f format] profile + * TableName implements [Model.TableName] interface method. */ - use: string + tableName(): string + } + interface Settings { /** - * Aliases is an array of aliases that can be used instead of the first word in Use. + * PK implements [Model.LastSavedPK] interface method. */ - aliases: Array + lastSavedPK(): any + } + interface Settings { /** - * SuggestFor is an array of command names for which this command will be suggested - - * similar to aliases but only suggests. + * PK implements [Model.PK] interface method. */ - suggestFor: Array + pk(): any + } + interface Settings { /** - * Short is the short description shown in the 'help' output. + * IsNew implements [Model.IsNew] interface method. */ - short: string + isNew(): boolean + } + interface Settings { /** - * The group id under which this subcommand is grouped in the 'help' output of its parent. + * MarkAsNew implements [Model.MarkAsNew] interface method. */ - groupID: string + markAsNew(): void + } + interface Settings { /** - * Long is the long message shown in the 'help ' output. + * MarkAsNew implements [Model.MarkAsNotNew] interface method. */ - long: string + markAsNotNew(): void + } + interface Settings { /** - * Example is examples of how to use the command. + * PostScan implements [Model.PostScan] interface method. */ - example: string + postScan(): void + } + interface Settings { /** - * ValidArgs is list of all valid non-flag arguments that are accepted in shell completions + * String returns a serialized string representation of the current settings. */ - validArgs: Array + string(): string + } + interface Settings { /** - * ValidArgsFunction is an optional function that provides valid non-flag arguments for shell completion. - * It is a dynamic version of using ValidArgs. - * Only one of ValidArgs and ValidArgsFunction can be used for a command. + * DBExport prepares and exports the current settings for db persistence. */ - validArgsFunction: (cmd: Command, args: Array, toComplete: string) => [Array, ShellCompDirective] + dbExport(app: App): _TygojaDict + } + interface Settings { /** - * Expected arguments + * PostValidate implements the [PostValidator] interface and defines + * the Settings model validations. */ - args: PositionalArgs + postValidate(ctx: context.Context, app: App): void + } + interface Settings { /** - * ArgAliases is List of aliases for ValidArgs. - * These are not suggested to the user in the shell completion, - * but accepted if entered manually. + * Merge merges the "other" settings into the current one. */ - argAliases: Array + merge(other: Settings): void + } + interface Settings { /** - * BashCompletionFunction is custom bash functions used by the legacy bash autocompletion generator. - * For portability with other shells, it is recommended to instead use ValidArgsFunction + * Clone creates a new deep copy of the current settings. */ - bashCompletionFunction: string + clone(): (Settings) + } + interface Settings { /** - * Deprecated defines, if this command is deprecated and should print this string when used. - */ - deprecated: string - /** - * Annotations are key/value pairs that can be used by applications to identify or - * group commands or set special options. + * MarshalJSON implements the [json.Marshaler] interface. + * + * Note that sensitive fields (S3 secret, SMTP password, etc.) are excluded. */ - annotations: _TygojaDict + marshalJSON(): string|Array + } + interface SMTPConfig { + enabled: boolean + port: number + host: string + username: string + password: string /** - * Version defines the version for this command. If this value is non-empty and the command does not - * define a "version" flag, a "version" boolean flag will be added to the command and, if specified, - * will print content of the "Version" variable. A shorthand "v" flag will also be added if the - * command does not define one. + * SMTP AUTH - PLAIN (default) or LOGIN */ - version: string + authMethod: string /** - * The *Run functions are executed in the following order: - * ``` - * * PersistentPreRun() - * * PreRun() - * * Run() - * * PostRun() - * * PersistentPostRun() - * ``` - * All functions get the same args, the arguments after the command name. - * The *PreRun and *PostRun functions will only be executed if the Run function of the current - * command has been declared. + * Whether to enforce TLS encryption for the mail server connection. * - * PersistentPreRun: children of this command will inherit and execute. + * When set to false StartTLS command is send, leaving the server + * to decide whether to upgrade the connection or not. */ - persistentPreRun: (cmd: Command, args: Array) => void + tls: boolean /** - * PersistentPreRunE: PersistentPreRun but returns an error. + * LocalName is optional domain name or IP address used for the + * EHLO/HELO exchange (if not explicitly set, defaults to "localhost"). + * + * This is required only by some SMTP servers, such as Gmail SMTP-relay. */ - persistentPreRunE: (cmd: Command, args: Array) => void + localName: string + } + interface SMTPConfig { /** - * PreRun: children of this command will not inherit. + * Validate makes SMTPConfig validatable by implementing [validation.Validatable] interface. */ - preRun: (cmd: Command, args: Array) => void + validate(): void + } + interface S3Config { + enabled: boolean + bucket: string + region: string + endpoint: string + accessKey: string + secret: string + forcePathStyle: boolean + } + interface S3Config { /** - * PreRunE: PreRun but returns an error. + * Validate makes S3Config validatable by implementing [validation.Validatable] interface. */ - preRunE: (cmd: Command, args: Array) => void + validate(): void + } + interface BatchConfig { + enabled: boolean /** - * Run: Typically the actual work function. Most commands will only implement this. + * MaxRequests is the maximum allowed batch request to execute. */ - run: (cmd: Command, args: Array) => void + maxRequests: number /** - * RunE: Run but returns an error. + * Timeout is the the max duration in seconds to wait before cancelling the batch transaction. */ - runE: (cmd: Command, args: Array) => void + timeout: number /** - * PostRun: run after the Run command. + * MaxBodySize is the maximum allowed batch request body size in bytes. + * + * If not set, fallbacks to max ~128MB. */ - postRun: (cmd: Command, args: Array) => void + maxBodySize: number + } + interface BatchConfig { /** - * PostRunE: PostRun but returns an error. + * Validate makes BatchConfig validatable by implementing [validation.Validatable] interface. */ - postRunE: (cmd: Command, args: Array) => void + validate(): void + } + interface BackupsConfig { /** - * PersistentPostRun: children of this command will inherit and execute after PostRun. + * Cron is a cron expression to schedule auto backups, eg. "* * * * *". + * + * Leave it empty to disable the auto backups functionality. */ - persistentPostRun: (cmd: Command, args: Array) => void + cron: string /** - * PersistentPostRunE: PersistentPostRun but returns an error. + * CronMaxKeep is the the max number of cron generated backups to + * keep before removing older entries. + * + * This field works only when the cron config has valid cron expression. */ - persistentPostRunE: (cmd: Command, args: Array) => void + cronMaxKeep: number /** - * FParseErrWhitelist flag parse errors to be ignored + * S3 is an optional S3 storage config specifying where to store the app backups. */ - fParseErrWhitelist: FParseErrWhitelist + s3: S3Config + } + interface BackupsConfig { /** - * CompletionOptions is a set of options to control the handling of shell completion + * Validate makes BackupsConfig validatable by implementing [validation.Validatable] interface. */ - completionOptions: CompletionOptions + validate(): void + } + interface MetaConfig { + appName: string + appURL: string + senderName: string + senderAddress: string + hideControls: boolean + } + interface MetaConfig { /** - * TraverseChildren parses flags on all parents before executing child command. + * Validate makes MetaConfig validatable by implementing [validation.Validatable] interface. */ - traverseChildren: boolean + validate(): void + } + interface LogsConfig { + maxDays: number + minLevel: number + logIP: boolean + logAuthId: boolean + } + interface LogsConfig { /** - * Hidden defines, if this command is hidden and should NOT show up in the list of available commands. + * Validate makes LogsConfig validatable by implementing [validation.Validatable] interface. */ - hidden: boolean + validate(): void + } + interface TrustedProxyConfig { /** - * SilenceErrors is an option to quiet errors down stream. + * Headers is a list of explicit trusted header(s) to check. */ - silenceErrors: boolean + headers: Array /** - * SilenceUsage is an option to silence usage when an error occurs. + * UseLeftmostIP specifies to use the left-mostish IP from the trusted headers. + * + * Note that this could be insecure when used with X-Forwarded-For header + * because some proxies like AWS ELB allow users to prepend their own header value + * before appending the trusted ones. */ - silenceUsage: boolean + useLeftmostIP: boolean + } + interface TrustedProxyConfig { /** - * DisableFlagParsing disables the flag parsing. - * If this is true all flags will be passed to the command as arguments. + * MarshalJSON implements the [json.Marshaler] interface. */ - disableFlagParsing: boolean + marshalJSON(): string|Array + } + interface TrustedProxyConfig { /** - * DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...") - * will be printed by generating docs for this command. + * Validate makes RateLimitRule validatable by implementing [validation.Validatable] interface. */ - disableAutoGenTag: boolean + validate(): void + } + interface RateLimitsConfig { + rules: Array + enabled: boolean + } + interface RateLimitsConfig { /** - * DisableFlagsInUseLine will disable the addition of [flags] to the usage - * line of a command when printing help or generating docs + * FindRateLimitRule returns the first matching rule based on the provided labels. + * + * Optionally you can further specify a list of valid RateLimitRule.Audience values to further filter the matching rule + * (aka. the rule Audience will have to exist in one of the specified options). */ - disableFlagsInUseLine: boolean + findRateLimitRule(searchLabels: Array, ...optOnlyAudience: string[]): [RateLimitRule, boolean] + } + interface RateLimitsConfig { /** - * DisableSuggestions disables the suggestions based on Levenshtein distance - * that go along with 'unknown command' messages. + * MarshalJSON implements the [json.Marshaler] interface. */ - disableSuggestions: boolean + marshalJSON(): string|Array + } + interface RateLimitsConfig { /** - * SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions. - * Must be > 0. + * Validate makes RateLimitsConfig validatable by implementing [validation.Validatable] interface. */ - suggestionsMinimumDistance: number + validate(): void } - interface Command { + interface RateLimitRule { /** - * Context returns underlying command context. If command was executed - * with ExecuteContext or the context was set with SetContext, the - * previously set context will be returned. Otherwise, nil is returned. + * Label is the identifier of the current rule. * - * Notice that a call to Execute and ExecuteC will replace a nil context of - * a command with a context.Background, so a background context will be - * returned by Context after one of these functions has been called. + * It could be a tag, complete path or path prerefix (when ends with `/`). + * + * Example supported labels: + * ``` + * - test_a (plain text "tag") + * - users:create + * - *:create + * - / + * - /api + * - POST /api/collections/ + * ``` */ - context(): context.Context - } - interface Command { + label: string /** - * SetContext sets context for the command. This context will be overwritten by - * Command.ExecuteContext or Command.ExecuteContextC. + * Audience specifies the auth group the rule should apply for: + * ``` + * - "" - both guests and authenticated users (default) + * - "@guest" - only for guests + * - "@auth" - only for authenticated users + * ``` */ - setContext(ctx: context.Context): void - } - interface Command { + audience: string /** - * SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden - * particularly useful when testing. + * Duration specifies the interval (in seconds) per which to reset + * the counted/accumulated rate limiter tokens. */ - setArgs(a: Array): void - } - interface Command { + duration: number /** - * SetOutput sets the destination for usage and error messages. - * If output is nil, os.Stderr is used. - * Deprecated: Use SetOut and/or SetErr instead + * MaxRequests is the max allowed number of requests per Duration. */ - setOutput(output: io.Writer): void + maxRequests: number } - interface Command { + interface RateLimitRule { /** - * SetOut sets the destination for usage messages. - * If newOut is nil, os.Stdout is used. + * Validate makes RateLimitRule validatable by implementing [validation.Validatable] interface. */ - setOut(newOut: io.Writer): void + validate(): void } - interface Command { + interface RateLimitRule { /** - * SetErr sets the destination for error messages. - * If newErr is nil, os.Stderr is used. + * DurationTime returns the tag's Duration as [time.Duration]. */ - setErr(newErr: io.Writer): void + durationTime(): time.Duration } - interface Command { + interface RateLimitRule { /** - * SetIn sets the source for input data - * If newIn is nil, os.Stdin is used. + * String returns a string representation of the rule. */ - setIn(newIn: io.Reader): void + string(): string } - interface Command { + type _sNDhNqv = BaseModel + interface Param extends _sNDhNqv { + created: types.DateTime + updated: types.DateTime + value: types.JSONRaw + } + interface Param { + tableName(): string + } + interface BaseApp { /** - * SetUsageFunc sets usage function. Usage can be defined by application. + * ReloadSettings initializes and reloads the stored application settings. + * + * If no settings were stored it will persist the current app ones. */ - setUsageFunc(f: (_arg0: Command) => void): void + reloadSettings(): void } - interface Command { + interface BaseApp { /** - * SetUsageTemplate sets usage template. Can be defined by Application. + * DeleteView drops the specified view name. + * + * This method is a no-op if a view with the provided name doesn't exist. + * + * NB! Be aware that this method is vulnerable to SQL injection and the + * "name" argument must come only from trusted input! */ - setUsageTemplate(s: string): void + deleteView(name: string): void } - interface Command { + interface BaseApp { /** - * SetFlagErrorFunc sets a function to generate an error when flag parsing - * fails. + * SaveView creates (or updates already existing) persistent SQL view. + * + * NB! Be aware that this method is vulnerable to SQL injection and the + * "selectQuery" argument must come only from trusted input! */ - setFlagErrorFunc(f: (_arg0: Command, _arg1: Error) => void): void + saveView(name: string, selectQuery: string): void } - interface Command { + interface BaseApp { /** - * SetHelpFunc sets help function. Can be defined by Application. + * CreateViewFields creates a new FieldsList from the provided select query. + * + * There are some caveats: + * - The select query must have an "id" column. + * - Wildcard ("*") columns are not supported to avoid accidentally leaking sensitive data. */ - setHelpFunc(f: (_arg0: Command, _arg1: Array) => void): void + createViewFields(selectQuery: string): FieldsList } - interface Command { + interface BaseApp { /** - * SetHelpCommand sets help command. + * FindRecordByViewFile returns the original Record of the provided view collection file. */ - setHelpCommand(cmd: Command): void + findRecordByViewFile(viewCollectionModelOrIdentifier: any, fileFieldName: string, filename: string): (Record) } - interface Command { + interface queryField { + } + interface identifier { + } + interface identifiersParser { + } +} + +/** + * Package mails implements various helper methods for sending common + * emails like forgotten password, verification, etc. + */ +namespace mails { + interface sendRecordAuthAlert { /** - * SetHelpCommandGroupID sets the group id of the help command. + * SendRecordAuthAlert sends a new device login alert to the specified auth record. */ - setHelpCommandGroupID(groupID: string): void + (app: CoreApp, authRecord: core.Record, info: string): void } - interface Command { + interface sendRecordOTP { /** - * SetCompletionCommandGroupID sets the group id of the completion command. + * SendRecordOTP sends OTP email to the specified auth record. + * + * This method will also update the "sentTo" field of the related OTP record to the mail sent To address (if the OTP exists and not already assigned). */ - setCompletionCommandGroupID(groupID: string): void + (app: CoreApp, authRecord: core.Record, otpId: string, pass: string): void } - interface Command { + interface sendRecordPasswordReset { /** - * SetHelpTemplate sets help template to be used. Application can use it to set custom template. + * SendRecordPasswordReset sends a password reset request email to the specified auth record. */ - setHelpTemplate(s: string): void + (app: CoreApp, authRecord: core.Record): void } - interface Command { + interface sendRecordVerification { /** - * SetVersionTemplate sets version template to be used. Application can use it to set custom template. + * SendRecordVerification sends a verification request email to the specified auth record. */ - setVersionTemplate(s: string): void + (app: CoreApp, authRecord: core.Record): void } - interface Command { + interface sendRecordChangeEmail { /** - * SetErrPrefix sets error message prefix to be used. Application can use it to set custom prefix. + * SendRecordChangeEmail sends a change email confirmation email to the specified auth record. */ - setErrPrefix(s: string): void + (app: CoreApp, authRecord: core.Record, newEmail: string): void } - interface Command { +} + +namespace forms { + // @ts-ignore + import validation = ozzo_validation + /** + * AppleClientSecretCreate is a form struct to generate a new Apple Client Secret. + * + * Reference: https://developer.apple.com/documentation/sign_in_with_apple/generate_and_validate_tokens + */ + interface AppleClientSecretCreate { /** - * SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands. - * The user should not have a cyclic dependency on commands. + * ClientId is the identifier of your app (aka. Service ID). */ - setGlobalNormalizationFunc(n: (f: any, name: string) => any): void - } - interface Command { + clientId: string /** - * OutOrStdout returns output to stdout. + * TeamId is a 10-character string associated with your developer account + * (usually could be found next to your name in the Apple Developer site). */ - outOrStdout(): io.Writer - } - interface Command { + teamId: string /** - * OutOrStderr returns output to stderr + * KeyId is a 10-character key identifier generated for the "Sign in with Apple" + * private key associated with your developer account. */ - outOrStderr(): io.Writer - } - interface Command { + keyId: string /** - * ErrOrStderr returns output to stderr + * PrivateKey is the private key associated to your app. + * Usually wrapped within -----BEGIN PRIVATE KEY----- X -----END PRIVATE KEY-----. */ - errOrStderr(): io.Writer - } - interface Command { + privateKey: string /** - * InOrStdin returns input to stdin + * Duration specifies how long the generated JWT should be considered valid. + * The specified value must be in seconds and max 15777000 (~6months). */ - inOrStdin(): io.Reader + duration: number } - interface Command { + interface newAppleClientSecretCreate { /** - * UsageFunc returns either the function set by SetUsageFunc for this command - * or a parent, or it returns a default usage function. + * NewAppleClientSecretCreate creates a new [AppleClientSecretCreate] form with initializer + * config created from the provided [CoreApp] instances. */ - usageFunc(): (_arg0: Command) => void + (app: CoreApp): (AppleClientSecretCreate) } - interface Command { + interface AppleClientSecretCreate { /** - * Usage puts out the usage for the command. - * Used when a user provides invalid input. - * Can be defined by user by overriding UsageFunc. + * Validate makes the form validatable by implementing [validation.Validatable] interface. */ - usage(): void + validate(): void } - interface Command { + interface AppleClientSecretCreate { /** - * HelpFunc returns either the function set by SetHelpFunc for this command - * or a parent, or it returns a function with default help behavior. + * Submit validates the form and returns a new Apple Client Secret JWT. */ - helpFunc(): (_arg0: Command, _arg1: Array) => void + submit(): string } - interface Command { - /** - * Help puts out the help for the command. - * Used when a user calls help [command]. - * Can be defined by user by overriding HelpFunc. - */ - help(): void + interface RecordUpsert { } - interface Command { + interface newRecordUpsert { /** - * UsageString returns usage string. + * NewRecordUpsert creates a new [RecordUpsert] form from the provided [CoreApp] and [core.Record] instances + * (for create you could pass a pointer to an empty Record - core.NewRecord(collection)). */ - usageString(): string + (app: CoreApp, record: core.Record): (RecordUpsert) } - interface Command { + interface RecordUpsert { /** - * FlagErrorFunc returns either the function set by SetFlagErrorFunc for this - * command or a parent, or it returns a function which returns the original - * error. + * SetContext assigns ctx as context of the current form. */ - flagErrorFunc(): (_arg0: Command, _arg1: Error) => void + setContext(ctx: context.Context): void } - interface Command { + interface RecordUpsert { /** - * UsagePadding return padding for the usage. + * SetApp replaces the current form app instance. + * + * This could be used for example if you want to change at later stage + * before submission to change from regular -> transactional app instance. */ - usagePadding(): number + setApp(app: CoreApp): void } - interface Command { + interface RecordUpsert { /** - * CommandPathPadding return padding for the command path. + * SetRecord replaces the current form record instance. */ - commandPathPadding(): number + setRecord(record: core.Record): void } - interface Command { + interface RecordUpsert { /** - * NamePadding returns padding for the name. + * ResetAccess resets the form access level to the accessLevelDefault. */ - namePadding(): number + resetAccess(): void } - interface Command { + interface RecordUpsert { /** - * UsageTemplate returns usage template for the command. + * GrantManagerAccess updates the form access level to "manager" allowing + * directly changing some system record fields (often used with auth collection records). */ - usageTemplate(): string + grantManagerAccess(): void } - interface Command { + interface RecordUpsert { /** - * HelpTemplate return help template for the command. + * GrantSuperuserAccess updates the form access level to "superuser" allowing + * directly changing all system record fields, including those marked as "Hidden". */ - helpTemplate(): string + grantSuperuserAccess(): void } - interface Command { + interface RecordUpsert { /** - * VersionTemplate return version template for the command. + * HasManageAccess reports whether the form has "manager" or "superuser" level access. */ - versionTemplate(): string + hasManageAccess(): boolean } - interface Command { + interface RecordUpsert { /** - * ErrPrefix return error message prefix for the command + * Load loads the provided data into the form and the related record. */ - errPrefix(): string + load(data: _TygojaDict): void } - interface Command { + interface RecordUpsert { /** - * Find the target command given the args and command tree - * Meant to be run on the highest node. Only searches down. + * Deprecated: It was previously used as part of the record create action but it is not needed anymore and will be removed in the future. + * + * DrySubmit performs a temp form submit within a transaction and reverts it at the end. + * For actual record persistence, check the [RecordUpsert.Submit()] method. + * + * This method doesn't perform validations, handle file uploads/deletes or trigger app save events! */ - find(args: Array): [(Command), Array] + drySubmit(callback: (txApp: CoreApp, drySavedRecord: core.Record) => void): void } - interface Command { + interface RecordUpsert { /** - * Traverse the command tree to find the command, and parse args for - * each parent. + * Submit validates the form specific validations and attempts to save the form record. */ - traverse(args: Array): [(Command), Array] + submit(): void } - interface Command { - /** - * SuggestionsFor provides suggestions for the typedName. - */ - suggestionsFor(typedName: string): Array + /** + * TestEmailSend is a email template test request form. + */ + interface TestEmailSend { + email: string + template: string + collection: string // optional, fallbacks to _superusers } - interface Command { + interface newTestEmailSend { /** - * VisitParents visits all parents of the command and invokes fn on each parent. + * NewTestEmailSend creates and initializes new TestEmailSend form. */ - visitParents(fn: (_arg0: Command) => void): void + (app: CoreApp): (TestEmailSend) } - interface Command { + interface TestEmailSend { /** - * Root finds root command. + * Validate makes the form validatable by implementing [validation.Validatable] interface. */ - root(): (Command) + validate(): void } - interface Command { + interface TestEmailSend { /** - * ArgsLenAtDash will return the length of c.Flags().Args at the moment - * when a -- was found during args parsing. + * Submit validates and sends a test email to the form.Email address. */ - argsLenAtDash(): number + submit(): void } - interface Command { + /** + * TestS3Filesystem defines a S3 filesystem connection test. + */ + interface TestS3Filesystem { /** - * ExecuteContext is the same as Execute(), but sets the ctx on the command. - * Retrieve ctx by calling cmd.Context() inside your *Run lifecycle or ValidArgs - * functions. + * The name of the filesystem - storage or backups */ - executeContext(ctx: context.Context): void + filesystem: string } - interface Command { + interface newTestS3Filesystem { /** - * Execute uses the args (os.Args[1:] by default) - * and run through the command tree finding appropriate matches - * for commands and then corresponding flags. + * NewTestS3Filesystem creates and initializes new TestS3Filesystem form. */ - execute(): void + (app: CoreApp): (TestS3Filesystem) } - interface Command { + interface TestS3Filesystem { /** - * ExecuteContextC is the same as ExecuteC(), but sets the ctx on the command. - * Retrieve ctx by calling cmd.Context() inside your *Run lifecycle or ValidArgs - * functions. + * Validate makes the form validatable by implementing [validation.Validatable] interface. */ - executeContextC(ctx: context.Context): (Command) + validate(): void } - interface Command { + interface TestS3Filesystem { /** - * ExecuteC executes the command. + * Submit validates and performs a S3 filesystem connection test. */ - executeC(): (Command) - } - interface Command { - validateArgs(args: Array): void + submit(): void } - interface Command { +} + +/** + * Package template is a thin wrapper around the standard html/template + * and text/template packages that implements a convenient registry to + * load and cache templates on the fly concurrently. + * + * It was created to assist the JSVM plugin HTML rendering, but could be used in other Go code. + * + * Example: + * + * ``` + * registry := template.NewRegistry() + * + * html1, err := registry.LoadFiles( + * // the files set wil be parsed only once and then cached + * "layout.html", + * "content.html", + * ).Render(map[string]any{"name": "John"}) + * + * html2, err := registry.LoadFiles( + * // reuse the already parsed and cached files set + * "layout.html", + * "content.html", + * ).Render(map[string]any{"name": "Jane"}) + * ``` + */ +namespace template { + interface newRegistry { /** - * ValidateRequiredFlags validates all required flags are present and returns an error otherwise + * NewRegistry creates and initializes a new templates registry with + * some defaults (eg. global "raw" template function for unescaped HTML). + * + * Use the Registry.Load* methods to load templates into the registry. */ - validateRequiredFlags(): void + (): (Registry) } - interface Command { + /** + * Registry defines a templates registry that is safe to be used by multiple goroutines. + * + * Use the Registry.Load* methods to load templates into the registry. + */ + interface Registry { + } + interface Registry { /** - * InitDefaultHelpFlag adds default help flag to c. - * It is called automatically by executing the c or by calling help and usage. - * If c already has help flag, it will do nothing. + * AddFuncs registers new global template functions. + * + * The key of each map entry is the function name that will be used in the templates. + * If a function with the map entry name already exists it will be replaced with the new one. + * + * The value of each map entry is a function that must have either a + * single return value, or two return values of which the second has type error. + * + * Example: + * + * ``` + * r.AddFuncs(map[string]any{ + * "toUpper": func(str string) string { + * return strings.ToUppser(str) + * }, + * ... + * }) + * ``` */ - initDefaultHelpFlag(): void + addFuncs(funcs: _TygojaDict): (Registry) } - interface Command { + interface Registry { /** - * InitDefaultVersionFlag adds default version flag to c. - * It is called automatically by executing the c. - * If c already has a version flag, it will do nothing. - * If c.Version is empty, it will do nothing. + * LoadFiles caches (if not already) the specified filenames set as a + * single template and returns a ready to use Renderer instance. + * + * There must be at least 1 filename specified. */ - initDefaultVersionFlag(): void + loadFiles(...filenames: string[]): (Renderer) } - interface Command { + interface Registry { /** - * InitDefaultHelpCmd adds default help command to c. - * It is called automatically by executing the c or by calling help and usage. - * If c already has help command or c has no subcommands, it will do nothing. + * LoadString caches (if not already) the specified inline string as a + * single template and returns a ready to use Renderer instance. */ - initDefaultHelpCmd(): void + loadString(text: string): (Renderer) } - interface Command { + interface Registry { /** - * ResetCommands delete parent, subcommand and help command from c. + * LoadFS caches (if not already) the specified fs and globPatterns + * pair as single template and returns a ready to use Renderer instance. + * + * There must be at least 1 file matching the provided globPattern(s) + * (note that most file names serves as glob patterns matching themselves). */ - resetCommands(): void + loadFS(fsys: fs.FS, ...globPatterns: string[]): (Renderer) } - interface Command { - /** - * Commands returns a sorted slice of child commands. - */ - commands(): Array<(Command | undefined)> + /** + * Renderer defines a single parsed template. + */ + interface Renderer { } - interface Command { + interface Renderer { /** - * AddCommand adds one or more commands to this parent command. + * Render executes the template with the specified data as the dot object + * and returns the result as plain string. */ - addCommand(...cmds: (Command | undefined)[]): void + render(data: any): string } - interface Command { +} + +namespace apis { + interface toApiError { /** - * Groups returns a slice of child command groups. + * ToApiError wraps err into ApiError instance (if not already). */ - groups(): Array<(Group | undefined)> + (err: Error): (router.ApiError) } - interface Command { + interface newApiError { /** - * AllChildCommandsHaveGroup returns if all subcommands are assigned to a group + * NewApiError is an alias for [router.NewApiError]. */ - allChildCommandsHaveGroup(): boolean + (status: number, message: string, errData: any): (router.ApiError) } - interface Command { + interface newBadRequestError { /** - * ContainsGroup return if groupID exists in the list of command groups. + * NewBadRequestError is an alias for [router.NewBadRequestError]. */ - containsGroup(groupID: string): boolean + (message: string, errData: any): (router.ApiError) } - interface Command { + interface newNotFoundError { /** - * AddGroup adds one or more command groups to this parent command. + * NewNotFoundError is an alias for [router.NewNotFoundError]. */ - addGroup(...groups: (Group | undefined)[]): void + (message: string, errData: any): (router.ApiError) } - interface Command { + interface newForbiddenError { /** - * RemoveCommand removes one or more commands from a parent command. + * NewForbiddenError is an alias for [router.NewForbiddenError]. */ - removeCommand(...cmds: (Command | undefined)[]): void + (message: string, errData: any): (router.ApiError) } - interface Command { + interface newUnauthorizedError { /** - * Print is a convenience method to Print to the defined output, fallback to Stderr if not set. + * NewUnauthorizedError is an alias for [router.NewUnauthorizedError]. */ - print(...i: { - }[]): void + (message: string, errData: any): (router.ApiError) } - interface Command { + interface newTooManyRequestsError { /** - * Println is a convenience method to Println to the defined output, fallback to Stderr if not set. + * NewTooManyRequestsError is an alias for [router.NewTooManyRequestsError]. */ - println(...i: { - }[]): void + (message: string, errData: any): (router.ApiError) } - interface Command { + interface newInternalServerError { /** - * Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set. + * NewInternalServerError is an alias for [router.NewInternalServerError]. */ - printf(format: string, ...i: { - }[]): void + (message: string, errData: any): (router.ApiError) } - interface Command { - /** - * PrintErr is a convenience method to Print to the defined Err output, fallback to Stderr if not set. - */ - printErr(...i: { - }[]): void + interface backupFileInfo { + modified: types.DateTime + key: string + size: number } - interface Command { + // @ts-ignore + import validation = ozzo_validation + interface backupCreateForm { + name: string + } + interface backupUploadForm { + file?: filesystem.File + } + interface newRouter { /** - * PrintErrln is a convenience method to Println to the defined Err output, fallback to Stderr if not set. + * NewRouter returns a new router instance loaded with the default app middlewares and api routes. */ - printErrln(...i: { - }[]): void + (app: CoreApp): (router.Router) } - interface Command { + interface wrapStdHandler { /** - * PrintErrf is a convenience method to Printf to the defined Err output, fallback to Stderr if not set. + * WrapStdHandler wraps Go [http.Handler] into a PocketBase handler func. */ - printErrf(format: string, ...i: { - }[]): void + (h: http.Handler): (_arg0: core.RequestEvent) => void } - interface Command { + interface wrapStdMiddleware { /** - * CommandPath returns the full path to this command. + * WrapStdMiddleware wraps Go [func(http.Handler) http.Handle] into a PocketBase middleware func. */ - commandPath(): string + (m: (_arg0: http.Handler) => http.Handler): (_arg0: core.RequestEvent) => void } - interface Command { + interface mustSubFS { /** - * UseLine puts out the full usage for a given command (including parents). + * MustSubFS returns an [fs.FS] corresponding to the subtree rooted at fsys's dir. + * + * This is similar to [fs.Sub] but panics on failure. */ - useLine(): string + (fsys: fs.FS, dir: string): fs.FS } - interface Command { + interface _static { /** - * DebugFlags used to determine which flags have been assigned to which commands - * and which persist. + * Static is a handler function to serve static directory content from fsys. + * + * If a file resource is missing and indexFallback is set, the request + * will be forwarded to the base index.html (useful for SPA with pretty urls). + * + * NB! Expects the route to have a "{path...}" wildcard parameter. + * + * Special redirects: + * ``` + * - if "path" is a file that ends in index.html, it is redirected to its non-index.html version (eg. /test/index.html -> /test/) + * - if "path" is a directory that has index.html, the index.html file is rendered, + * otherwise if missing - returns 404 or fallback to the root index.html if indexFallback is set + * ``` + * + * Example: + * + * ``` + * fsys := os.DirFS("./pb_public") + * router.GET("/files/{path...}", apis.Static(fsys, false)) + * ``` */ - debugFlags(): void + (fsys: fs.FS, indexFallback: boolean): (_arg0: core.RequestEvent) => void } - interface Command { + interface HandleFunc {(e: core.RequestEvent): void } + interface BatchActionHandlerFunc {(app: CoreApp, ir: core.InternalRequest, params: _TygojaDict, next: (data: any) => void): HandleFunc } + interface BatchRequestResult { + body: any + status: number + } + interface batchRequestsForm { + requests: Array<(core.InternalRequest | undefined)> + } + interface batchProcessor { + } + interface batchProcessor { + process(batch: Array<(core.InternalRequest | undefined)>, timeout: time.Duration): void + } + interface BatchResponseError { + } + interface BatchResponseError { + error(): string + } + interface BatchResponseError { + code(): string + } + interface BatchResponseError { + resolve(errData: _TygojaDict): any + } + interface BatchResponseError { + marshalJSON(): string|Array + } + interface collectionsImportForm { + collections: Array<_TygojaDict> + deleteMissing: boolean + } + interface fileApi { + } + interface defaultInstallerFunc { /** - * Name returns the command's name: the first word in the use line. + * DefaultInstallerFunc is the default PocketBase installer function. + * + * It will attempt to open a link in the browser (with a short-lived auth + * token for the systemSuperuser) to the installer UI so that users can + * create their own custom superuser record. + * + * See https://github.com/pocketbase/pocketbase/discussions/5814. */ - name(): string + (app: CoreApp, systemSuperuser: core.Record, baseURL: string): void } - interface Command { + interface requireGuestOnly { /** - * HasAlias determines if a given string is an alias of the command. + * RequireGuestOnly middleware requires a request to NOT have a valid + * Authorization header. + * + * This middleware is the opposite of [apis.RequireAuth()]. */ - hasAlias(s: string): boolean + (): (hook.Handler) } - interface Command { + interface requireAuth { /** - * CalledAs returns the command name or alias that was used to invoke - * this command or an empty string if the command has not been called. + * RequireAuth middleware requires a request to have a valid record Authorization header. + * + * The auth record could be from any collection. + * You can further filter the allowed record auth collections by specifying their names. + * + * Example: + * + * ``` + * apis.RequireAuth() // any auth collection + * apis.RequireAuth("_superusers", "users") // only the listed auth collections + * ``` */ - calledAs(): string + (...optCollectionNames: string[]): (hook.Handler) } - interface Command { + interface requireSuperuserAuth { /** - * NameAndAliases returns a list of the command name and all aliases + * RequireSuperuserAuth middleware requires a request to have + * a valid superuser Authorization header. */ - nameAndAliases(): string + (): (hook.Handler) } - interface Command { + interface requireSuperuserOrOwnerAuth { /** - * HasExample determines if the command has example. + * RequireSuperuserOrOwnerAuth middleware requires a request to have + * a valid superuser or regular record owner Authorization header set. + * + * This middleware is similar to [apis.RequireAuth()] but + * for the auth record token expects to have the same id as the path + * parameter ownerIdPathParam (default to "id" if empty). */ - hasExample(): boolean + (ownerIdPathParam: string): (hook.Handler) } - interface Command { + interface requireSameCollectionContextAuth { /** - * Runnable determines if the command is itself runnable. + * RequireSameCollectionContextAuth middleware requires a request to have + * a valid record Authorization header and the auth record's collection to + * match the one from the route path parameter (default to "collection" if collectionParam is empty). */ - runnable(): boolean + (collectionPathParam: string): (hook.Handler) } - interface Command { + interface skipSuccessActivityLog { /** - * HasSubCommands determines if the command has children commands. + * SkipSuccessActivityLog is a helper middleware that instructs the global + * activity logger to log only requests that have failed/returned an error. */ - hasSubCommands(): boolean + (): (hook.Handler) } - interface Command { + interface bodyLimit { /** - * IsAvailableCommand determines if a command is available as a non-help command - * (this includes all non deprecated/hidden commands). + * BodyLimit returns a middleware handler that changes the default request body size limit. + * + * If limitBytes <= 0, no limit is applied. + * + * Otherwise, if the request body size exceeds the configured limitBytes, + * it sends 413 error response. */ - isAvailableCommand(): boolean + (limitBytes: number): (hook.Handler) } - interface Command { + type _sDTQrVU = io.ReadCloser + interface limitedReader extends _sDTQrVU { + } + interface limitedReader { + read(b: string|Array): number + } + interface limitedReader { + reread(): void + } + /** + * CORSConfig defines the config for CORS middleware. + */ + interface CORSConfig { /** - * IsAdditionalHelpTopicCommand determines if a command is an additional - * help topic command; additional help topic command is determined by the - * fact that it is NOT runnable/hidden/deprecated, and has no sub commands that - * are runnable/hidden/deprecated. - * Concrete example: https://github.com/spf13/cobra/issues/393#issuecomment-282741924. + * AllowOrigins determines the value of the Access-Control-Allow-Origin + * response header. This header defines a list of origins that may access the + * resource. The wildcard characters '*' and '?' are supported and are + * converted to regex fragments '.*' and '.' accordingly. + * + * Security: use extreme caution when handling the origin, and carefully + * validate any logic. Remember that attackers may register hostile domain names. + * See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html + * + * Optional. Default value []string{"*"}. + * + * See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin */ - isAdditionalHelpTopicCommand(): boolean - } - interface Command { + allowOrigins: Array /** - * HasHelpSubCommands determines if a command has any available 'help' sub commands - * that need to be shown in the usage/help default template under 'additional help - * topics'. + * AllowOriginFunc is a custom function to validate the origin. It takes the + * origin as an argument and returns true if allowed or false otherwise. If + * an error is returned, it is returned by the handler. If this option is + * set, AllowOrigins is ignored. + * + * Security: use extreme caution when handling the origin, and carefully + * validate any logic. Remember that attackers may register hostile domain names. + * See https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html + * + * Optional. */ - hasHelpSubCommands(): boolean - } - interface Command { + allowOriginFunc: (origin: string) => boolean /** - * HasAvailableSubCommands determines if a command has available sub commands that - * need to be shown in the usage/help default template under 'available commands'. + * AllowMethods determines the value of the Access-Control-Allow-Methods + * response header. This header specified the list of methods allowed when + * accessing the resource. This is used in response to a preflight request. + * + * Optional. Default value DefaultCORSConfig.AllowMethods. + * + * See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods */ - hasAvailableSubCommands(): boolean - } - interface Command { + allowMethods: Array /** - * HasParent determines if the command is a child command. + * AllowHeaders determines the value of the Access-Control-Allow-Headers + * response header. This header is used in response to a preflight request to + * indicate which HTTP headers can be used when making the actual request. + * + * Optional. Default value []string{}. + * + * See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers */ - hasParent(): boolean - } - interface Command { + allowHeaders: Array /** - * GlobalNormalizationFunc returns the global normalization function or nil if it doesn't exist. + * AllowCredentials determines the value of the + * Access-Control-Allow-Credentials response header. This header indicates + * whether or not the response to the request can be exposed when the + * credentials mode (Request.credentials) is true. When used as part of a + * response to a preflight request, this indicates whether or not the actual + * request can be made using credentials. See also + * [MDN: Access-Control-Allow-Credentials]. + * + * Optional. Default value false, in which case the header is not set. + * + * Security: avoid using `AllowCredentials = true` with `AllowOrigins = *`. + * See "Exploiting CORS misconfigurations for Bitcoins and bounties", + * https://blog.portswigger.net/2016/10/exploiting-cors-misconfigurations-for.html + * + * See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials */ - globalNormalizationFunc(): (f: any, name: string) => any - } - interface Command { + allowCredentials: boolean /** - * Flags returns the complete FlagSet that applies - * to this command (local and persistent declared here and by all parents). + * UnsafeWildcardOriginWithAllowCredentials UNSAFE/INSECURE: allows wildcard '*' origin to be used with AllowCredentials + * flag. In that case we consider any origin allowed and send it back to the client with `Access-Control-Allow-Origin` header. + * + * This is INSECURE and potentially leads to [cross-origin](https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties) + * attacks. See: https://github.com/labstack/echo/issues/2400 for discussion on the subject. + * + * Optional. Default value is false. */ - flags(): (any) - } - interface Command { + unsafeWildcardOriginWithAllowCredentials: boolean /** - * LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands. - * This function does not modify the flags of the current command, it's purpose is to return the current state. + * ExposeHeaders determines the value of Access-Control-Expose-Headers, which + * defines a list of headers that clients are allowed to access. + * + * Optional. Default value []string{}, in which case the header is not set. + * + * See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Header */ - localNonPersistentFlags(): (any) - } - interface Command { + exposeHeaders: Array /** - * LocalFlags returns the local FlagSet specifically set in the current command. - * This function does not modify the flags of the current command, it's purpose is to return the current state. + * MaxAge determines the value of the Access-Control-Max-Age response header. + * This header indicates how long (in seconds) the results of a preflight + * request can be cached. + * The header is set only if MaxAge != 0, negative value sends "0" which instructs browsers not to cache that response. + * + * Optional. Default value 0 - meaning header is not sent. + * + * See also: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age */ - localFlags(): (any) + maxAge: number } - interface Command { + interface cors { /** - * InheritedFlags returns all flags which were inherited from parent commands. - * This function does not modify the flags of the current command, it's purpose is to return the current state. + * CORS returns a CORS middleware. */ - inheritedFlags(): (any) + (config: CORSConfig): (hook.Handler) } - interface Command { + /** + * GzipConfig defines the config for Gzip middleware. + */ + interface GzipConfig { /** - * NonInheritedFlags returns all flags which were not inherited from parent commands. - * This function does not modify the flags of the current command, it's purpose is to return the current state. + * Gzip compression level. + * Optional. Default value -1. */ - nonInheritedFlags(): (any) - } - interface Command { + level: number /** - * PersistentFlags returns the persistent FlagSet specifically set in the current command. + * Length threshold before gzip compression is applied. + * Optional. Default value 0. + * + * Most of the time you will not need to change the default. Compressing + * a short response might increase the transmitted data because of the + * gzip format overhead. Compressing the response will also consume CPU + * and time on the server and the client (for decompressing). Depending on + * your use case such a threshold might be useful. + * + * See also: + * https://webmasters.stackexchange.com/questions/31750/what-is-recommended-minimum-object-size-for-gzip-performance-benefits */ - persistentFlags(): (any) + minLength: number } - interface Command { + interface gzip { /** - * ResetFlags deletes all flags from command. + * Gzip returns a middleware which compresses HTTP response using Gzip compression scheme. */ - resetFlags(): void + (): (hook.Handler) } - interface Command { + interface gzipWithConfig { /** - * HasFlags checks if the command contains any flags (local plus persistent from the entire structure). + * GzipWithConfig returns a middleware which compresses HTTP response using gzip compression scheme. */ - hasFlags(): boolean + (config: GzipConfig): (hook.Handler) } - interface Command { - /** - * HasPersistentFlags checks if the command contains persistent flags. - */ - hasPersistentFlags(): boolean + type _swEZnBj = http.ResponseWriter&io.Writer + interface gzipResponseWriter extends _swEZnBj { } - interface Command { - /** - * HasLocalFlags checks if the command has flags specifically declared locally. - */ - hasLocalFlags(): boolean + interface gzipResponseWriter { + writeHeader(code: number): void } - interface Command { - /** - * HasInheritedFlags checks if the command has flags inherited from its parent command. - */ - hasInheritedFlags(): boolean + interface gzipResponseWriter { + write(b: string|Array): number } - interface Command { - /** - * HasAvailableFlags checks if the command contains any flags (local plus persistent from the entire - * structure) which are not hidden or deprecated. - */ - hasAvailableFlags(): boolean + interface gzipResponseWriter { + flush(): void } - interface Command { + interface gzipResponseWriter { + hijack(): [net.Conn, (bufio.ReadWriter)] + } + interface gzipResponseWriter { + push(target: string, opts: http.PushOptions): void + } + interface gzipResponseWriter { + unwrap(): http.ResponseWriter + } + type _sPDwysn = sync.RWMutex + interface rateLimiter extends _sPDwysn { + } + /** + * @todo evaluate swiching to a more traditional fixed window or sliding window counter + * implementations since some users complained that it is not intuitive (see #7329). + * + * rateClient is a mixture of token bucket and fixed window rate limit strategies + * that refills the allowance only after at least "interval" seconds + * has elapsed since the last request. + */ + type _sdlzXCp = sync.Mutex + interface rateClient extends _sdlzXCp { + } + interface realtimeSubscribeForm { + clientId: string + subscriptions: Array + } + /** + * recordData represents the broadcasted record subscrition message data. + */ + interface recordData { + record: any // map or core.Record + action: string + } + interface EmailChangeConfirmForm { + token: string + password: string + } + interface emailChangeRequestForm { + newEmail: string + } + interface impersonateForm { /** - * HasAvailablePersistentFlags checks if the command contains persistent flags which are not hidden or deprecated. + * Duration is the optional custom token duration in seconds. */ - hasAvailablePersistentFlags(): boolean + duration: number } - interface Command { + interface otpResponse { + enabled: boolean + duration: number // in seconds + } + interface mfaResponse { + enabled: boolean + duration: number // in seconds + } + interface passwordResponse { + identityFields: Array + enabled: boolean + } + interface oauth2Response { + providers: Array + enabled: boolean + } + interface providerInfo { + name: string + displayName: string + state: string + authURL: string /** - * HasAvailableLocalFlags checks if the command has flags specifically declared locally which are not hidden - * or deprecated. + * @todo + * deprecated: use AuthURL instead + * AuthUrl will be removed after dropping v0.22 support */ - hasAvailableLocalFlags(): boolean - } - interface Command { + authUrl: string /** - * HasAvailableInheritedFlags checks if the command has flags inherited from its parent command which are - * not hidden or deprecated. + * technically could be omitted if the provider doesn't support PKCE, + * but to avoid breaking existing typed clients we'll return them as empty string */ - hasAvailableInheritedFlags(): boolean + codeVerifier: string + codeChallenge: string + codeChallengeMethod: string } - interface Command { + interface authMethodsResponse { + password: passwordResponse + oauth2: oauth2Response + mfa: mfaResponse + otp: otpResponse /** - * Flag climbs up the command tree looking for matching flag. + * legacy fields + * @todo remove after dropping v0.22 support */ - flag(name: string): (any) + authProviders: Array + usernamePassword: boolean + emailPassword: boolean } - interface Command { + interface createOTPForm { + email: string + } + interface recordConfirmPasswordResetForm { + token: string + password: string + passwordConfirm: string + } + interface recordRequestPasswordResetForm { + email: string + } + interface recordConfirmVerificationForm { + token: string + } + interface recordRequestVerificationForm { + email: string + } + interface recordOAuth2LoginForm { /** - * ParseFlags parses persistent flag tree and local flags. + * Additional data that will be used for creating a new auth record + * if an existing OAuth2 account doesn't exist. */ - parseFlags(args: Array): void - } - interface Command { + createData: _TygojaDict /** - * Parent returns a commands parent command. + * The name of the OAuth2 client provider (eg. "google") */ - parent(): (Command) - } - interface Command { + provider: string /** - * RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag. + * The authorization code returned from the initial request. */ - registerFlagCompletionFunc(flagName: string, f: (cmd: Command, args: Array, toComplete: string) => [Array, ShellCompDirective]): void - } - interface Command { + code: string /** - * GetFlagCompletionFunc returns the completion function for the given flag of the command, if available. + * The optional PKCE code verifier as part of the code_challenge sent with the initial request. */ - getFlagCompletionFunc(flagName: string): [(_arg0: Command, _arg1: Array, _arg2: string) => [Array, ShellCompDirective], boolean] - } - interface Command { + codeVerifier: string /** - * InitDefaultCompletionCmd adds a default 'completion' command to c. - * This function will do nothing if any of the following is true: - * 1- the feature has been explicitly disabled by the program, - * 2- c has no subcommands (to avoid creating one), - * 3- c already has a 'completion' command provided by the program. + * The redirect url sent with the initial request. */ - initDefaultCompletionCmd(): void - } - interface Command { + redirectURL: string /** - * GenFishCompletion generates fish completion file and writes to the passed writer. + * @todo + * deprecated: use RedirectURL instead + * RedirectUrl will be removed after dropping v0.22 support */ - genFishCompletion(w: io.Writer, includeDesc: boolean): void + redirectUrl: string } - interface Command { + interface oauth2RedirectData { + state: string + code: string + error: string /** - * GenFishCompletionFile generates fish completion file. + * returned by Apple only */ - genFishCompletionFile(filename: string, includeDesc: boolean): void + appleUser: string } - interface Command { + interface authWithOTPForm { + otpId: string + password: string + } + interface authWithPasswordForm { + identity: string + password: string /** - * MarkFlagsRequiredTogether marks the given flags with annotations so that Cobra errors - * if the command is invoked with a subset (but not all) of the given flags. + * IdentityField specifies the field to use to search for the identity + * (leave it empty for "auto" detection). */ - markFlagsRequiredTogether(...flagNames: string[]): void + identityField: string } - interface Command { + // @ts-ignore + import cryptoRand = rand + interface recordAuthResponse { /** - * MarkFlagsOneRequired marks the given flags with annotations so that Cobra errors - * if the command is invoked without at least one flag from the given set of flags. + * RecordAuthResponse writes standardized json record auth response + * into the specified request context. + * + * The authMethod argument specify the name of the current authentication method (eg. password, oauth2, etc.) + * that it is used primarily as an auth identifier during MFA and for login alerts. + * + * Set authMethod to empty string if you want to ignore the MFA checks and the login alerts + * (can be also adjusted additionally via the OnRecordAuthRequest hook). */ - markFlagsOneRequired(...flagNames: string[]): void + (e: core.RequestEvent, authRecord: core.Record, authMethod: string, meta: any): void } - interface Command { + interface enrichRecord { /** - * MarkFlagsMutuallyExclusive marks the given flags with annotations so that Cobra errors - * if the command is invoked with more than one flag from the given set of flags. + * EnrichRecord parses the request context and enrich the provided record: + * ``` + * - expands relations (if defaultExpands and/or ?expand query param is set) + * - ensures that the emails of the auth record and its expanded auth relations + * are visible only for the current logged superuser, record owner or record with manage access + * ``` */ - markFlagsMutuallyExclusive(...flagNames: string[]): void + (e: core.RequestEvent, record: core.Record, ...defaultExpands: string[]): void } - interface Command { + interface enrichRecords { /** - * ValidateFlagGroups validates the mutuallyExclusive/oneRequired/requiredAsGroup logic and returns the - * first error encountered. + * EnrichRecords parses the request context and enriches the provided records: + * ``` + * - expands relations (if defaultExpands and/or ?expand query param is set) + * - ensures that the emails of the auth records and their expanded auth relations + * are visible only for the current logged superuser, record owner or record with manage access + * ``` + * + * Note: Expects all records to be from the same collection! */ - validateFlagGroups(): void + (e: core.RequestEvent, records: Array<(core.Record | undefined)>, ...defaultExpands: string[]): void } - interface Command { + interface iterator { + } + /** + * ServeConfig defines a configuration struct for apis.Serve(). + */ + interface ServeConfig { /** - * GenPowerShellCompletionFile generates powershell completion file without descriptions. + * ShowStartBanner indicates whether to show or hide the server start console message. */ - genPowerShellCompletionFile(filename: string): void - } - interface Command { + showStartBanner: boolean /** - * GenPowerShellCompletion generates powershell completion file without descriptions - * and writes it to the passed writer. + * HttpAddr is the TCP address to listen for the HTTP server (eg. "127.0.0.1:80"). */ - genPowerShellCompletion(w: io.Writer): void - } - interface Command { + httpAddr: string /** - * GenPowerShellCompletionFileWithDesc generates powershell completion file with descriptions. + * HttpsAddr is the TCP address to listen for the HTTPS server (eg. "127.0.0.1:443"). */ - genPowerShellCompletionFileWithDesc(filename: string): void - } - interface Command { + httpsAddr: string /** - * GenPowerShellCompletionWithDesc generates powershell completion file with descriptions - * and writes it to the passed writer. + * Optional domains list to use when issuing the TLS certificate. + * + * If not set, the host from the bound server address will be used. + * + * For convenience, for each "non-www" domain a "www" entry and + * redirect will be automatically added. */ - genPowerShellCompletionWithDesc(w: io.Writer): void - } - interface Command { + certificateDomains: Array /** - * MarkFlagRequired instructs the various shell completion implementations to - * prioritize the named flag when performing completion, - * and causes your command to report an error if invoked without the flag. + * AllowedOrigins is an optional list of CORS origins (default to "*"). */ - markFlagRequired(name: string): void + allowedOrigins: Array } - interface Command { + interface serve { /** - * MarkPersistentFlagRequired instructs the various shell completion implementations to - * prioritize the named persistent flag when performing completion, - * and causes your command to report an error if invoked without the flag. + * Serve starts a new app web server. + * + * NB! The app should be bootstrapped before starting the web server. + * + * Example: + * + * ``` + * app.Bootstrap() + * apis.Serve(app, apis.ServeConfig{ + * HttpAddr: "127.0.0.1:8080", + * ShowStartBanner: false, + * }) + * ``` */ - markPersistentFlagRequired(name: string): void + (app: CoreApp, config: ServeConfig): void } - interface Command { - /** - * MarkFlagFilename instructs the various shell completion implementations to - * limit completions for the named flag to the specified file extensions. - */ - markFlagFilename(name: string, ...extensions: string[]): void + interface serverErrorLogWriter { } - interface Command { - /** - * MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. - * The bash completion script will call the bash function f for the flag. - * - * This will only work for bash completion. - * It is recommended to instead use c.RegisterFlagCompletionFunc(...) which allows - * to register a Go function which will work across all shells. - */ - markFlagCustom(name: string, f: string): void + interface serverErrorLogWriter { + write(p: string|Array): number } - interface Command { +} + +namespace pocketbase { + /** + * PocketBase defines a PocketBase app launcher. + * + * It implements [CoreApp] via embedding and all of the app interface methods + * could be accessed directly through the instance (eg. PocketBase.DataDir()). + */ + type _stNaIDS = CoreApp + interface PocketBase extends _stNaIDS { /** - * MarkPersistentFlagFilename instructs the various shell completion - * implementations to limit completions for the named persistent flag to the - * specified file extensions. + * RootCmd is the main console command */ - markPersistentFlagFilename(name: string, ...extensions: string[]): void + rootCmd?: cobra.Command } - interface Command { + /** + * Config is the PocketBase initialization config struct. + */ + interface Config { /** - * MarkFlagDirname instructs the various shell completion implementations to - * limit completions for the named flag to directory names. + * hide the default console server info on app startup */ - markFlagDirname(name: string): void - } - interface Command { + hideStartBanner: boolean /** - * MarkPersistentFlagDirname instructs the various shell completion - * implementations to limit completions for the named persistent flag to - * directory names. + * optional default values for the console flags */ - markPersistentFlagDirname(name: string): void - } - interface Command { + defaultDev: boolean + defaultDataDir: string // if not set, it will fallback to "./pb_data" + defaultEncryptionEnv: string + defaultQueryTimeout: time.Duration // default to core.DefaultQueryTimeout (in seconds) /** - * GenZshCompletionFile generates zsh completion file including descriptions. + * optional DB configurations */ - genZshCompletionFile(filename: string): void + dataMaxOpenConns: number // default to core.DefaultDataMaxOpenConns + dataMaxIdleConns: number // default to core.DefaultDataMaxIdleConns + auxMaxOpenConns: number // default to core.DefaultAuxMaxOpenConns + auxMaxIdleConns: number // default to core.DefaultAuxMaxIdleConns + dbConnect: core.DBConnectFunc // default to core.dbConnect } - interface Command { + interface _new { /** - * GenZshCompletion generates zsh completion file including descriptions - * and writes it to the passed writer. + * New creates a new PocketBase instance with the default configuration. + * Use [NewWithConfig] if you want to provide a custom configuration. + * + * Note that the application will not be initialized/bootstrapped yet, + * aka. DB connections, migrations, app settings, etc. will not be accessible. + * Everything will be initialized when [PocketBase.Start] is executed. + * If you want to initialize the application before calling [PocketBase.Start], + * then you'll have to manually call [PocketBase.Bootstrap]. */ - genZshCompletion(w: io.Writer): void + (): (PocketBase) } - interface Command { + interface newWithConfig { /** - * GenZshCompletionFileNoDesc generates zsh completion file without descriptions. + * NewWithConfig creates a new PocketBase instance with the provided config. + * + * Note that the application will not be initialized/bootstrapped yet, + * aka. DB connections, migrations, app settings, etc. will not be accessible. + * Everything will be initialized when [PocketBase.Start] is executed. + * If you want to initialize the application before calling [PocketBase.Start], + * then you'll have to manually call [PocketBase.Bootstrap]. */ - genZshCompletionFileNoDesc(filename: string): void + (config: Config): (PocketBase) } - interface Command { + interface PocketBase { /** - * GenZshCompletionNoDesc generates zsh completion file without descriptions - * and writes it to the passed writer. + * Start starts the application, aka. registers the default system + * commands (serve, superuser, version) and executes pb.RootCmd. */ - genZshCompletionNoDesc(w: io.Writer): void + start(): void } - interface Command { + interface PocketBase { /** - * MarkZshCompPositionalArgumentFile only worked for zsh and its behavior was - * not consistent with Bash completion. It has therefore been disabled. - * Instead, when no other completion is specified, file completion is done by - * default for every argument. One can disable file completion on a per-argument - * basis by using ValidArgsFunction and ShellCompDirectiveNoFileComp. - * To achieve file extension filtering, one can use ValidArgsFunction and - * ShellCompDirectiveFilterFileExt. + * Execute initializes the application (if not already) and executes + * the pb.RootCmd with graceful shutdown support. * - * Deprecated + * This method differs from pb.Start() by not registering the default + * system commands! */ - markZshCompPositionalArgumentFile(argPosition: number, ...patterns: string[]): void + execute(): void } - interface Command { + /** + * coloredWriter is a small wrapper struct to construct a [color.Color] writter. + */ + interface coloredWriter { + } + interface coloredWriter { /** - * MarkZshCompPositionalArgumentWords only worked for zsh. It has therefore - * been disabled. - * To achieve the same behavior across all shells, one can use - * ValidArgs (for the first argument only) or ValidArgsFunction for - * any argument (can include the first one also). - * - * Deprecated + * Write writes the p bytes using the colored writer. */ - markZshCompPositionalArgumentWords(argPosition: number, ...words: string[]): void + write(p: string|Array): number } } /** - * Package syscall contains an interface to the low-level operating system - * primitives. The details vary depending on the underlying system, and - * by default, godoc will display the syscall documentation for the current - * system. If you want godoc to display syscall documentation for another - * system, set $GOOS and $GOARCH to the desired system. For example, if - * you want to view documentation for freebsd/arm on linux/amd64, set $GOOS - * to freebsd and $GOARCH to arm. - * The primary use of syscall is inside other packages that provide a more - * portable interface to the system, such as "os", "time" and "net". Use - * those packages rather than this one if you can. - * For details of the functions and data types in this package consult - * the manuals for the appropriate operating system. - * These calls return err == nil to indicate success; otherwise - * err is an operating system error describing the failure. - * On most systems, that error has type [Errno]. + * Package sync provides basic synchronization primitives such as mutual + * exclusion locks. Other than the [Once] and [WaitGroup] types, most are intended + * for use by low-level library routines. Higher-level synchronization is + * better done via channels and communication. * - * NOTE: Most of the functions, types, and constants defined in - * this package are also available in the [golang.org/x/sys] package. - * That package has more system call support than this one, - * and most new code should prefer that package where possible. - * See https://golang.org/s/go1.4-syscall for more information. + * Values containing the types defined in this package should not be copied. */ -namespace syscall { +namespace sync { + // @ts-ignore + import isync = sync /** - * SysProcIDMap holds Container ID to Host ID mappings used for User Namespaces in Linux. - * See user_namespaces(7). + * A Mutex is a mutual exclusion lock. + * The zero value for a Mutex is an unlocked mutex. * - * Note that User Namespaces are not available on a number of popular Linux - * versions (due to security issues), or are available but subject to AppArmor - * restrictions like in Ubuntu 24.04. + * A Mutex must not be copied after first use. + * + * In the terminology of [the Go memory model], + * the n'th call to [Mutex.Unlock] “synchronizes before” the m'th call to [Mutex.Lock] + * for any n < m. + * A successful call to [Mutex.TryLock] is equivalent to a call to Lock. + * A failed call to TryLock does not establish any “synchronizes before” + * relation at all. + * + * [the Go memory model]: https://go.dev/ref/mem */ - interface SysProcIDMap { - containerID: number // Container ID. - hostID: number // Host ID. - size: number // Size. + interface Mutex { } - // @ts-ignore - import errorspkg = errors - /** - * Credential holds user and group identities to be assumed - * by a child process started by [StartProcess]. - */ - interface Credential { - uid: number // User ID. - gid: number // Group ID. - groups: Array // Supplementary group IDs. - noSetGroups: boolean // If true, don't set supplementary groups + interface Mutex { + /** + * Lock locks m. + * If the lock is already in use, the calling goroutine + * blocks until the mutex is available. + */ + lock(): void + } + interface Mutex { + /** + * TryLock tries to lock m and reports whether it succeeded. + * + * Note that while correct uses of TryLock do exist, they are rare, + * and use of TryLock is often a sign of a deeper problem + * in a particular use of mutexes. + */ + tryLock(): boolean + } + interface Mutex { + /** + * Unlock unlocks m. + * It is a run-time error if m is not locked on entry to Unlock. + * + * A locked [Mutex] is not associated with a particular goroutine. + * It is allowed for one goroutine to lock a Mutex and then + * arrange for another goroutine to unlock it. + */ + unlock(): void } - // @ts-ignore - import runtimesyscall = syscall /** - * A Signal is a number describing a process signal. - * It implements the [os.Signal] interface. + * A RWMutex is a reader/writer mutual exclusion lock. + * The lock can be held by an arbitrary number of readers or a single writer. + * The zero value for a RWMutex is an unlocked mutex. + * + * A RWMutex must not be copied after first use. + * + * If any goroutine calls [RWMutex.Lock] while the lock is already held by + * one or more readers, concurrent calls to [RWMutex.RLock] will block until + * the writer has acquired (and released) the lock, to ensure that + * the lock eventually becomes available to the writer. + * Note that this prohibits recursive read-locking. + * A [RWMutex.RLock] cannot be upgraded into a [RWMutex.Lock], + * nor can a [RWMutex.Lock] be downgraded into a [RWMutex.RLock]. + * + * In the terminology of [the Go memory model], + * the n'th call to [RWMutex.Unlock] “synchronizes before” the m'th call to Lock + * for any n < m, just as for [Mutex]. + * For any call to RLock, there exists an n such that + * the n'th call to Unlock “synchronizes before” that call to RLock, + * and the corresponding call to [RWMutex.RUnlock] “synchronizes before” + * the n+1'th call to Lock. + * + * [the Go memory model]: https://go.dev/ref/mem */ - interface Signal extends Number{} - interface Signal { - signal(): void + interface RWMutex { } - interface Signal { - string(): string + interface RWMutex { + /** + * RLock locks rw for reading. + * + * It should not be used for recursive read locking; a blocked Lock + * call excludes new readers from acquiring the lock. See the + * documentation on the [RWMutex] type. + */ + rLock(): void + } + interface RWMutex { + /** + * TryRLock tries to lock rw for reading and reports whether it succeeded. + * + * Note that while correct uses of TryRLock do exist, they are rare, + * and use of TryRLock is often a sign of a deeper problem + * in a particular use of mutexes. + */ + tryRLock(): boolean + } + interface RWMutex { + /** + * RUnlock undoes a single [RWMutex.RLock] call; + * it does not affect other simultaneous readers. + * It is a run-time error if rw is not locked for reading + * on entry to RUnlock. + */ + rUnlock(): void + } + interface RWMutex { + /** + * Lock locks rw for writing. + * If the lock is already locked for reading or writing, + * Lock blocks until the lock is available. + */ + lock(): void + } + interface RWMutex { + /** + * TryLock tries to lock rw for writing and reports whether it succeeded. + * + * Note that while correct uses of TryLock do exist, they are rare, + * and use of TryLock is often a sign of a deeper problem + * in a particular use of mutexes. + */ + tryLock(): boolean + } + interface RWMutex { + /** + * Unlock unlocks rw for writing. It is a run-time error if rw is + * not locked for writing on entry to Unlock. + * + * As with Mutexes, a locked [RWMutex] is not associated with a particular + * goroutine. One goroutine may [RWMutex.RLock] ([RWMutex.Lock]) a RWMutex and then + * arrange for another goroutine to [RWMutex.RUnlock] ([RWMutex.Unlock]) it. + */ + unlock(): void + } + interface RWMutex { + /** + * RLocker returns a [Locker] interface that implements + * the [Locker.Lock] and [Locker.Unlock] methods by calling rw.RLock and rw.RUnlock. + */ + rLocker(): Locker } } /** - * Package time provides functionality for measuring and displaying time. - * - * The calendrical calculations always assume a Gregorian calendar, with - * no leap seconds. - * - * # Monotonic Clocks - * - * Operating systems provide both a “wall clock,” which is subject to - * changes for clock synchronization, and a “monotonic clock,” which is - * not. The general rule is that the wall clock is for telling time and - * the monotonic clock is for measuring time. Rather than split the API, - * in this package the Time returned by [time.Now] contains both a wall - * clock reading and a monotonic clock reading; later time-telling - * operations use the wall clock reading, but later time-measuring - * operations, specifically comparisons and subtractions, use the - * monotonic clock reading. - * - * For example, this code always computes a positive elapsed time of - * approximately 20 milliseconds, even if the wall clock is changed during - * the operation being timed: + * Package io provides basic interfaces to I/O primitives. + * Its primary job is to wrap existing implementations of such primitives, + * such as those in package os, into shared public interfaces that + * abstract the functionality, plus some other related primitives. * - * ``` - * start := time.Now() - * ... operation that takes 20 milliseconds ... - * t := time.Now() - * elapsed := t.Sub(start) - * ``` - * - * Other idioms, such as [time.Since](start), [time.Until](deadline), and - * time.Now().Before(deadline), are similarly robust against wall clock - * resets. - * - * The rest of this section gives the precise details of how operations - * use monotonic clocks, but understanding those details is not required - * to use this package. - * - * The Time returned by time.Now contains a monotonic clock reading. - * If Time t has a monotonic clock reading, t.Add adds the same duration to - * both the wall clock and monotonic clock readings to compute the result. - * Because t.AddDate(y, m, d), t.Round(d), and t.Truncate(d) are wall time - * computations, they always strip any monotonic clock reading from their results. - * Because t.In, t.Local, and t.UTC are used for their effect on the interpretation - * of the wall time, they also strip any monotonic clock reading from their results. - * The canonical way to strip a monotonic clock reading is to use t = t.Round(0). - * - * If Times t and u both contain monotonic clock readings, the operations - * t.After(u), t.Before(u), t.Equal(u), t.Compare(u), and t.Sub(u) are carried out - * using the monotonic clock readings alone, ignoring the wall clock - * readings. If either t or u contains no monotonic clock reading, these - * operations fall back to using the wall clock readings. - * - * On some systems the monotonic clock will stop if the computer goes to sleep. - * On such a system, t.Sub(u) may not accurately reflect the actual - * time that passed between t and u. The same applies to other functions and - * methods that subtract times, such as [Since], [Until], [Before], [After], - * [Add], [Sub], [Equal] and [Compare]. In some cases, you may need to strip - * the monotonic clock to get accurate results. - * - * Because the monotonic clock reading has no meaning outside - * the current process, the serialized forms generated by t.GobEncode, - * t.MarshalBinary, t.MarshalJSON, and t.MarshalText omit the monotonic - * clock reading, and t.Format provides no format for it. Similarly, the - * constructors [time.Date], [time.Parse], [time.ParseInLocation], and [time.Unix], - * as well as the unmarshalers t.GobDecode, t.UnmarshalBinary. - * t.UnmarshalJSON, and t.UnmarshalText always create times with - * no monotonic clock reading. - * - * The monotonic clock reading exists only in [Time] values. It is not - * a part of [Duration] values or the Unix times returned by t.Unix and - * friends. - * - * Note that the Go == operator compares not just the time instant but - * also the [Location] and the monotonic clock reading. See the - * documentation for the Time type for a discussion of equality - * testing for Time values. - * - * For debugging, the result of t.String does include the monotonic - * clock reading if present. If t != u because of different monotonic clock readings, - * that difference will be visible when printing t.String() and u.String(). - * - * # Timer Resolution - * - * [Timer] resolution varies depending on the Go runtime, the operating system - * and the underlying hardware. - * On Unix, the resolution is ~1ms. - * On Windows version 1803 and newer, the resolution is ~0.5ms. - * On older Windows versions, the default resolution is ~16ms, but - * a higher resolution may be requested using [golang.org/x/sys/windows.TimeBeginPeriod]. + * Because these interfaces and primitives wrap lower-level operations with + * various implementations, unless otherwise informed clients should not + * assume they are safe for parallel execution. */ -namespace time { - /** - * A Month specifies a month of the year (January = 1, ...). - */ - interface Month extends Number{} - interface Month { - /** - * String returns the English name of the month ("January", "February", ...). - */ - string(): string - } +namespace io { /** - * A Weekday specifies a day of the week (Sunday = 0, ...). + * Reader is the interface that wraps the basic Read method. + * + * Read reads up to len(p) bytes into p. It returns the number of bytes + * read (0 <= n <= len(p)) and any error encountered. Even if Read + * returns n < len(p), it may use all of p as scratch space during the call. + * If some data is available but not len(p) bytes, Read conventionally + * returns what is available instead of waiting for more. + * + * When Read encounters an error or end-of-file condition after + * successfully reading n > 0 bytes, it returns the number of + * bytes read. It may return the (non-nil) error from the same call + * or return the error (and n == 0) from a subsequent call. + * An instance of this general case is that a Reader returning + * a non-zero number of bytes at the end of the input stream may + * return either err == EOF or err == nil. The next Read should + * return 0, EOF. + * + * Callers should always process the n > 0 bytes returned before + * considering the error err. Doing so correctly handles I/O errors + * that happen after reading some bytes and also both of the + * allowed EOF behaviors. + * + * If len(p) == 0, Read should always return n == 0. It may return a + * non-nil error if some error condition is known, such as EOF. + * + * Implementations of Read are discouraged from returning a + * zero byte count with a nil error, except when len(p) == 0. + * Callers should treat a return of 0 and nil as indicating that + * nothing happened; in particular it does not indicate EOF. + * + * Implementations must not retain p. */ - interface Weekday extends Number{} - interface Weekday { - /** - * String returns the English name of the day ("Sunday", "Monday", ...). - */ - string(): string + interface Reader { + [key:string]: any; + read(p: string|Array): number } /** - * A Location maps time instants to the zone in use at that time. - * Typically, the Location represents the collection of time offsets - * in use in a geographical area. For many Locations the time offset varies - * depending on whether daylight savings time is in use at the time instant. + * Writer is the interface that wraps the basic Write method. * - * Location is used to provide a time zone in a printed Time value and for - * calculations involving intervals that may cross daylight savings time - * boundaries. + * Write writes len(p) bytes from p to the underlying data stream. + * It returns the number of bytes written from p (0 <= n <= len(p)) + * and any error encountered that caused the write to stop early. + * Write must return a non-nil error if it returns n < len(p). + * Write must not modify the slice data, even temporarily. + * + * Implementations must not retain p. */ - interface Location { - } - interface Location { - /** - * String returns a descriptive name for the time zone information, - * corresponding to the name argument to [LoadLocation] or [FixedZone]. - */ - string(): string + interface Writer { + [key:string]: any; + write(p: string|Array): number } -} - -/** - * Package context defines the Context type, which carries deadlines, - * cancellation signals, and other request-scoped values across API boundaries - * and between processes. - * - * Incoming requests to a server should create a [Context], and outgoing - * calls to servers should accept a Context. The chain of function - * calls between them must propagate the Context, optionally replacing - * it with a derived Context created using [WithCancel], [WithDeadline], - * [WithTimeout], or [WithValue]. When a Context is canceled, all - * Contexts derived from it are also canceled. - * - * The [WithCancel], [WithDeadline], and [WithTimeout] functions take a - * Context (the parent) and return a derived Context (the child) and a - * [CancelFunc]. Calling the CancelFunc cancels the child and its - * children, removes the parent's reference to the child, and stops - * any associated timers. Failing to call the CancelFunc leaks the - * child and its children until the parent is canceled or the timer - * fires. The go vet tool checks that CancelFuncs are used on all - * control-flow paths. - * - * The [WithCancelCause] function returns a [CancelCauseFunc], which - * takes an error and records it as the cancellation cause. Calling - * [Cause] on the canceled context or any of its children retrieves - * the cause. If no cause is specified, Cause(ctx) returns the same - * value as ctx.Err(). - * - * Programs that use Contexts should follow these rules to keep interfaces - * consistent across packages and enable static analysis tools to check context - * propagation: - * - * Do not store Contexts inside a struct type; instead, pass a Context - * explicitly to each function that needs it. The Context should be the first - * parameter, typically named ctx: - * - * ``` - * func DoSomething(ctx context.Context, arg Arg) error { - * // ... use ctx ... - * } - * ``` - * - * Do not pass a nil [Context], even if a function permits it. Pass [context.TODO] - * if you are unsure about which Context to use. - * - * Use context Values only for request-scoped data that transits processes and - * APIs, not for passing optional parameters to functions. - * - * The same Context may be passed to functions running in different goroutines; - * Contexts are safe for simultaneous use by multiple goroutines. - * - * See https://blog.golang.org/context for example code for a server that uses - * Contexts. - */ -namespace context { -} - -/** - * Package io provides basic interfaces to I/O primitives. - * Its primary job is to wrap existing implementations of such primitives, - * such as those in package os, into shared public interfaces that - * abstract the functionality, plus some other related primitives. - * - * Because these interfaces and primitives wrap lower-level operations with - * various implementations, unless otherwise informed clients should not - * assume they are safe for parallel execution. - */ -namespace io { /** * ReadCloser is the interface that groups the basic Read and Close methods. */ @@ -14943,1740 +14877,1339 @@ namespace io { [key:string]: any; } /** - * WriteCloser is the interface that groups the basic Write and Close methods. + * ReadSeekCloser is the interface that groups the basic Read, Seek and Close + * methods. */ - interface WriteCloser { + interface ReadSeekCloser { [key:string]: any; } } /** - * Package fs defines basic interfaces to a file system. - * A file system can be provided by the host operating system - * but also by other packages. - * - * See the [testing/fstest] package for support with testing - * implementations of file systems. - */ -namespace fs { -} - -/** - * Package url parses URLs and implements query escaping. + * Package bytes implements functions for the manipulation of byte slices. + * It is analogous to the facilities of the [strings] package. */ -namespace url { +namespace bytes { /** - * A URL represents a parsed URL (technically, a URI reference). - * - * The general form represented is: - * - * ``` - * [scheme:][//[userinfo@]host][/]path[?query][#fragment] - * ``` - * - * URLs that do not start with a slash after the scheme are interpreted as: - * - * ``` - * scheme:opaque[?query][#fragment] - * ``` - * - * The Host field contains the host and port subcomponents of the URL. - * When the port is present, it is separated from the host with a colon. - * When the host is an IPv6 address, it must be enclosed in square brackets: - * "[fe80::1]:80". The [net.JoinHostPort] function combines a host and port - * into a string suitable for the Host field, adding square brackets to - * the host when necessary. - * - * Note that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/. - * A consequence is that it is impossible to tell which slashes in the Path were - * slashes in the raw URL and which were %2f. This distinction is rarely important, - * but when it is, the code should use the [URL.EscapedPath] method, which preserves - * the original encoding of Path. - * - * The RawPath field is an optional field which is only set when the default - * encoding of Path is different from the escaped path. See the EscapedPath method - * for more details. - * - * URL's String method uses the EscapedPath method to obtain the path. + * A Reader implements the [io.Reader], [io.ReaderAt], [io.WriterTo], [io.Seeker], + * [io.ByteScanner], and [io.RuneScanner] interfaces by reading from + * a byte slice. + * Unlike a [Buffer], a Reader is read-only and supports seeking. + * The zero value for Reader operates like a Reader of an empty slice. */ - interface URL { - scheme: string - opaque: string // encoded opaque data - user?: Userinfo // username and password information - host: string // host or host:port (see Hostname and Port methods) - path: string // path (relative paths may omit leading slash) - rawPath: string // encoded path hint (see EscapedPath method) - omitHost: boolean // do not emit empty host (authority) - forceQuery: boolean // append a query ('?') even if RawQuery is empty - rawQuery: string // encoded query values, without '?' - fragment: string // fragment for references, without '#' - rawFragment: string // encoded fragment hint (see EscapedFragment method) + interface Reader { } - interface URL { + interface Reader { /** - * EscapedPath returns the escaped form of u.Path. - * In general there are multiple possible escaped forms of any path. - * EscapedPath returns u.RawPath when it is a valid escaping of u.Path. - * Otherwise EscapedPath ignores u.RawPath and computes an escaped - * form on its own. - * The [URL.String] and [URL.RequestURI] methods use EscapedPath to construct - * their results. - * In general, code should call EscapedPath instead of - * reading u.RawPath directly. + * Len returns the number of bytes of the unread portion of the + * slice. */ - escapedPath(): string + len(): number } - interface URL { + interface Reader { /** - * EscapedFragment returns the escaped form of u.Fragment. - * In general there are multiple possible escaped forms of any fragment. - * EscapedFragment returns u.RawFragment when it is a valid escaping of u.Fragment. - * Otherwise EscapedFragment ignores u.RawFragment and computes an escaped - * form on its own. - * The [URL.String] method uses EscapedFragment to construct its result. - * In general, code should call EscapedFragment instead of - * reading u.RawFragment directly. + * Size returns the original length of the underlying byte slice. + * Size is the number of bytes available for reading via [Reader.ReadAt]. + * The result is unaffected by any method calls except [Reader.Reset]. */ - escapedFragment(): string + size(): number } - interface URL { + interface Reader { /** - * String reassembles the [URL] into a valid URL string. - * The general form of the result is one of: - * - * ``` - * scheme:opaque?query#fragment - * scheme://userinfo@host/path?query#fragment - * ``` - * - * If u.Opaque is non-empty, String uses the first form; - * otherwise it uses the second form. - * Any non-ASCII characters in host are escaped. - * To obtain the path, String uses u.EscapedPath(). - * - * In the second form, the following rules apply: - * ``` - * - if u.Scheme is empty, scheme: is omitted. - * - if u.User is nil, userinfo@ is omitted. - * - if u.Host is empty, host/ is omitted. - * - if u.Scheme and u.Host are empty and u.User is nil, - * the entire scheme://userinfo@host/ is omitted. - * - if u.Host is non-empty and u.Path begins with a /, - * the form host/path does not add its own /. - * - if u.RawQuery is empty, ?query is omitted. - * - if u.Fragment is empty, #fragment is omitted. - * ``` + * Read implements the [io.Reader] interface. */ - string(): string + read(b: string|Array): number } - interface URL { + interface Reader { /** - * Redacted is like [URL.String] but replaces any password with "xxxxx". - * Only the password in u.User is redacted. + * ReadAt implements the [io.ReaderAt] interface. */ - redacted(): string + readAt(b: string|Array, off: number): number } - /** - * Values maps a string key to a list of values. - * It is typically used for query parameters and form values. - * Unlike in the http.Header map, the keys in a Values map - * are case-sensitive. - */ - interface Values extends _TygojaDict{} - interface Values { + interface Reader { /** - * Get gets the first value associated with the given key. - * If there are no values associated with the key, Get returns - * the empty string. To access multiple values, use the map - * directly. + * ReadByte implements the [io.ByteReader] interface. */ - get(key: string): string + readByte(): number } - interface Values { + interface Reader { /** - * Set sets the key to value. It replaces any existing - * values. + * UnreadByte complements [Reader.ReadByte] in implementing the [io.ByteScanner] interface. */ - set(key: string, value: string): void + unreadByte(): void } - interface Values { + interface Reader { /** - * Add adds the value to key. It appends to any existing - * values associated with key. + * ReadRune implements the [io.RuneReader] interface. */ - add(key: string, value: string): void + readRune(): [number, number] } - interface Values { + interface Reader { /** - * Del deletes the values associated with key. + * UnreadRune complements [Reader.ReadRune] in implementing the [io.RuneScanner] interface. */ - del(key: string): void + unreadRune(): void } - interface Values { + interface Reader { /** - * Has checks whether a given key is set. + * Seek implements the [io.Seeker] interface. */ - has(key: string): boolean + seek(offset: number, whence: number): number } - interface Values { + interface Reader { /** - * Encode encodes the values into “URL encoded” form - * ("bar=baz&foo=quux") sorted by key. + * WriteTo implements the [io.WriterTo] interface. */ - encode(): string + writeTo(w: io.Writer): number } - interface URL { + interface Reader { /** - * IsAbs reports whether the [URL] is absolute. - * Absolute means that it has a non-empty scheme. + * Reset resets the [Reader] to be reading from b. */ - isAbs(): boolean + reset(b: string|Array): void } - interface URL { +} + +/** + * Package syscall contains an interface to the low-level operating system + * primitives. The details vary depending on the underlying system, and + * by default, godoc will display the syscall documentation for the current + * system. If you want godoc to display syscall documentation for another + * system, set $GOOS and $GOARCH to the desired system. For example, if + * you want to view documentation for freebsd/arm on linux/amd64, set $GOOS + * to freebsd and $GOARCH to arm. + * The primary use of syscall is inside other packages that provide a more + * portable interface to the system, such as "os", "time" and "net". Use + * those packages rather than this one if you can. + * For details of the functions and data types in this package consult + * the manuals for the appropriate operating system. + * These calls return err == nil to indicate success; otherwise + * err is an operating system error describing the failure. + * On most systems, that error has type [Errno]. + * + * NOTE: Most of the functions, types, and constants defined in + * this package are also available in the [golang.org/x/sys] package. + * That package has more system call support than this one, + * and most new code should prefer that package where possible. + * See https://golang.org/s/go1.4-syscall for more information. + */ +namespace syscall { + // @ts-ignore + import errpkg = errors + interface SysProcAttr { + chroot: string // Chroot. + credential?: Credential // Credential. /** - * Parse parses a [URL] in the context of the receiver. The provided URL - * may be relative or absolute. Parse returns nil, err on parse - * failure, otherwise its return value is the same as [URL.ResolveReference]. + * Ptrace tells the child to call ptrace(PTRACE_TRACEME). + * Call runtime.LockOSThread before starting a process with this set, + * and don't call UnlockOSThread until done with PtraceSyscall calls. */ - parse(ref: string): (URL) - } - interface URL { + ptrace: boolean + setsid: boolean // Create session. /** - * ResolveReference resolves a URI reference to an absolute URI from - * an absolute base URI u, per RFC 3986 Section 5.2. The URI reference - * may be relative or absolute. ResolveReference always returns a new - * [URL] instance, even if the returned URL is identical to either the - * base or reference. If ref is an absolute URL, then ResolveReference - * ignores base and returns a copy of ref. + * Setpgid sets the process group ID of the child to Pgid, + * or, if Pgid == 0, to the new child's process ID. */ - resolveReference(ref: URL): (URL) - } - interface URL { + setpgid: boolean /** - * Query parses RawQuery and returns the corresponding values. - * It silently discards malformed value pairs. - * To check errors use [ParseQuery]. + * Setctty sets the controlling terminal of the child to + * file descriptor Ctty. Ctty must be a descriptor number + * in the child process: an index into ProcAttr.Files. + * This is only meaningful if Setsid is true. */ - query(): Values - } - interface URL { + setctty: boolean + noctty: boolean // Detach fd 0 from controlling terminal. + ctty: number // Controlling TTY fd. /** - * RequestURI returns the encoded path?query or opaque?query - * string that would be used in an HTTP request for u. + * Foreground places the child process group in the foreground. + * This implies Setpgid. The Ctty field must be set to + * the descriptor of the controlling TTY. + * Unlike Setctty, in this case Ctty must be a descriptor + * number in the parent process. */ - requestURI(): string - } - interface URL { + foreground: boolean + pgid: number // Child's process group ID if Setpgid. /** - * Hostname returns u.Host, stripping any valid port number if present. - * - * If the result is enclosed in square brackets, as literal IPv6 addresses are, - * the square brackets are removed from the result. + * Pdeathsig, if non-zero, is a signal that the kernel will send to + * the child process when the creating thread dies. Note that the signal + * is sent on thread termination, which may happen before process termination. + * There are more details at https://go.dev/issue/27505. */ - hostname(): string - } - interface URL { + pdeathsig: Signal + cloneflags: number // Flags for clone calls. + unshareflags: number // Flags for unshare calls. + uidMappings: Array // User ID mappings for user namespaces. + gidMappings: Array // Group ID mappings for user namespaces. /** - * Port returns the port part of u.Host, without the leading colon. - * - * If u.Host doesn't contain a valid numeric port, Port returns an empty string. + * GidMappingsEnableSetgroups enabling setgroups syscall. + * If false, then setgroups syscall will be disabled for the child process. + * This parameter is no-op if GidMappings == nil. Otherwise for unprivileged + * users this should be set to false for mappings work. */ - port(): string - } - interface URL { - marshalBinary(): string|Array - } - interface URL { - unmarshalBinary(text: string|Array): void - } - interface URL { + gidMappingsEnableSetgroups: boolean + ambientCaps: Array // Ambient capabilities. + useCgroupFD: boolean // Whether to make use of the CgroupFD field. + cgroupFD: number // File descriptor of a cgroup to put the new process into. /** - * JoinPath returns a new [URL] with the provided path elements joined to - * any existing path and the resulting path cleaned of any ./ or ../ elements. - * Any sequences of multiple / characters will be reduced to a single /. + * PidFD, if not nil, is used to store the pidfd of a child, if the + * functionality is supported by the kernel, or -1. Note *PidFD is + * changed only if the process starts successfully. */ - joinPath(...elem: string[]): (URL) + pidFD?: number } -} - -/** - * Package types implements some commonly used db serializable types - * like datetime, json, etc. - */ -namespace types { + // @ts-ignore + import errorspkg = errors /** - * DateTime represents a [time.Time] instance in UTC that is wrapped - * and serialized using the app default date layout. + * A RawConn is a raw network connection. */ - interface DateTime { - } - interface DateTime { + interface RawConn { + [key:string]: any; /** - * Time returns the internal [time.Time] instance. + * Control invokes f on the underlying connection's file + * descriptor or handle. + * The file descriptor fd is guaranteed to remain valid while + * f executes but not after f returns. */ - time(): time.Time - } - interface DateTime { + control(f: (fd: number) => void): void /** - * IsZero checks whether the current DateTime instance has zero time value. + * Read invokes f on the underlying connection's file + * descriptor or handle; f is expected to try to read from the + * file descriptor. + * If f returns true, Read returns. Otherwise Read blocks + * waiting for the connection to be ready for reading and + * tries again repeatedly. + * The file descriptor is guaranteed to remain valid while f + * executes but not after f returns. */ - isZero(): boolean - } - interface DateTime { + read(f: (fd: number) => boolean): void /** - * String serializes the current DateTime instance into a formatted - * UTC date string. - * - * The zero value is serialized to an empty string. + * Write is like Read but for writing. */ - string(): string + write(f: (fd: number) => boolean): void } - interface DateTime { - /** - * MarshalJSON implements the [json.Marshaler] interface. - */ - marshalJSON(): string|Array + // @ts-ignore + import runtimesyscall = syscall + /** + * An Errno is an unsigned number describing an error condition. + * It implements the error interface. The zero Errno is by convention + * a non-error, so code to convert from Errno to error should use: + * + * ``` + * err = nil + * if errno != 0 { + * err = errno + * } + * ``` + * + * Errno values can be tested against error values using [errors.Is]. + * For example: + * + * ``` + * _, _, err := syscall.Syscall(...) + * if errors.Is(err, fs.ErrNotExist) ... + * ``` + */ + interface Errno extends Number{} + interface Errno { + error(): string } - interface DateTime { - /** - * UnmarshalJSON implements the [json.Unmarshaler] interface. - */ - unmarshalJSON(b: string|Array): void + interface Errno { + is(target: Error): boolean } - interface DateTime { - /** - * Value implements the [driver.Valuer] interface. - */ - value(): any + interface Errno { + temporary(): boolean } - interface DateTime { - /** - * Scan implements [sql.Scanner] interface to scan the provided value - * into the current DateTime instance. - */ - scan(value: any): void + interface Errno { + timeout(): boolean } } /** - * Package net provides a portable interface for network I/O, including - * TCP/IP, UDP, domain name resolution, and Unix domain sockets. + * Package time provides functionality for measuring and displaying time. * - * Although the package provides access to low-level networking - * primitives, most clients will need only the basic interface provided - * by the [Dial], [Listen], and Accept functions and the associated - * [Conn] and [Listener] interfaces. The crypto/tls package uses - * the same interfaces and similar Dial and Listen functions. + * The calendrical calculations always assume a Gregorian calendar, with + * no leap seconds. * - * The Dial function connects to a server: + * # Monotonic Clocks * - * ``` - * conn, err := net.Dial("tcp", "golang.org:80") - * if err != nil { - * // handle error - * } - * fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n") - * status, err := bufio.NewReader(conn).ReadString('\n') - * // ... - * ``` + * Operating systems provide both a “wall clock,” which is subject to + * changes for clock synchronization, and a “monotonic clock,” which is + * not. The general rule is that the wall clock is for telling time and + * the monotonic clock is for measuring time. Rather than split the API, + * in this package the Time returned by [time.Now] contains both a wall + * clock reading and a monotonic clock reading; later time-telling + * operations use the wall clock reading, but later time-measuring + * operations, specifically comparisons and subtractions, use the + * monotonic clock reading. * - * The Listen function creates servers: + * For example, this code always computes a positive elapsed time of + * approximately 20 milliseconds, even if the wall clock is changed during + * the operation being timed: * * ``` - * ln, err := net.Listen("tcp", ":8080") - * if err != nil { - * // handle error - * } - * for { - * conn, err := ln.Accept() - * if err != nil { - * // handle error - * } - * go handleConnection(conn) - * } + * start := time.Now() + * ... operation that takes 20 milliseconds ... + * t := time.Now() + * elapsed := t.Sub(start) * ``` * - * # Name Resolution - * - * The method for resolving domain names, whether indirectly with functions like Dial - * or directly with functions like [LookupHost] and [LookupAddr], varies by operating system. - * - * On Unix systems, the resolver has two options for resolving names. - * It can use a pure Go resolver that sends DNS requests directly to the servers - * listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C - * library routines such as getaddrinfo and getnameinfo. + * Other idioms, such as [time.Since](start), [time.Until](deadline), and + * time.Now().Before(deadline), are similarly robust against wall clock + * resets. * - * On Unix the pure Go resolver is preferred over the cgo resolver, because a blocked DNS - * request consumes only a goroutine, while a blocked C call consumes an operating system thread. - * When cgo is available, the cgo-based resolver is used instead under a variety of - * conditions: on systems that do not let programs make direct DNS requests (OS X), - * when the LOCALDOMAIN environment variable is present (even if empty), - * when the RES_OPTIONS or HOSTALIASES environment variable is non-empty, - * when the ASR_CONFIG environment variable is non-empty (OpenBSD only), - * when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the - * Go resolver does not implement. + * The rest of this section gives the precise details of how operations + * use monotonic clocks, but understanding those details is not required + * to use this package. * - * On all systems (except Plan 9), when the cgo resolver is being used - * this package applies a concurrent cgo lookup limit to prevent the system - * from running out of system threads. Currently, it is limited to 500 concurrent lookups. + * The Time returned by time.Now contains a monotonic clock reading. + * If Time t has a monotonic clock reading, t.Add adds the same duration to + * both the wall clock and monotonic clock readings to compute the result. + * Because t.AddDate(y, m, d), t.Round(d), and t.Truncate(d) are wall time + * computations, they always strip any monotonic clock reading from their results. + * Because t.In, t.Local, and t.UTC are used for their effect on the interpretation + * of the wall time, they also strip any monotonic clock reading from their results. + * The canonical way to strip a monotonic clock reading is to use t = t.Round(0). * - * The resolver decision can be overridden by setting the netdns value of the - * GODEBUG environment variable (see package runtime) to go or cgo, as in: + * If Times t and u both contain monotonic clock readings, the operations + * t.After(u), t.Before(u), t.Equal(u), t.Compare(u), and t.Sub(u) are carried out + * using the monotonic clock readings alone, ignoring the wall clock + * readings. If either t or u contains no monotonic clock reading, these + * operations fall back to using the wall clock readings. * - * ``` - * export GODEBUG=netdns=go # force pure Go resolver - * export GODEBUG=netdns=cgo # force native resolver (cgo, win32) - * ``` + * On some systems the monotonic clock will stop if the computer goes to sleep. + * On such a system, t.Sub(u) may not accurately reflect the actual + * time that passed between t and u. The same applies to other functions and + * methods that subtract times, such as [Since], [Until], [Time.Before], [Time.After], + * [Time.Add], [Time.Equal] and [Time.Compare]. In some cases, you may need to strip + * the monotonic clock to get accurate results. * - * The decision can also be forced while building the Go source tree - * by setting the netgo or netcgo build tag. + * Because the monotonic clock reading has no meaning outside + * the current process, the serialized forms generated by t.GobEncode, + * t.MarshalBinary, t.MarshalJSON, and t.MarshalText omit the monotonic + * clock reading, and t.Format provides no format for it. Similarly, the + * constructors [time.Date], [time.Parse], [time.ParseInLocation], and [time.Unix], + * as well as the unmarshalers t.GobDecode, t.UnmarshalBinary. + * t.UnmarshalJSON, and t.UnmarshalText always create times with + * no monotonic clock reading. * - * A numeric netdns setting, as in GODEBUG=netdns=1, causes the resolver - * to print debugging information about its decisions. - * To force a particular resolver while also printing debugging information, - * join the two settings by a plus sign, as in GODEBUG=netdns=go+1. + * The monotonic clock reading exists only in [Time] values. It is not + * a part of [Duration] values or the Unix times returned by t.Unix and + * friends. * - * The Go resolver will send an EDNS0 additional header with a DNS request, - * to signal a willingness to accept a larger DNS packet size. - * This can reportedly cause sporadic failures with the DNS server run - * by some modems and routers. Setting GODEBUG=netedns0=0 will disable - * sending the additional header. + * Note that the Go == operator compares not just the time instant but + * also the [Location] and the monotonic clock reading. See the + * documentation for the Time type for a discussion of equality + * testing for Time values. * - * On macOS, if Go code that uses the net package is built with - * -buildmode=c-archive, linking the resulting archive into a C program - * requires passing -lresolv when linking the C code. + * For debugging, the result of t.String does include the monotonic + * clock reading if present. If t != u because of different monotonic clock readings, + * that difference will be visible when printing t.String() and u.String(). * - * On Plan 9, the resolver always accesses /net/cs and /net/dns. + * # Timer Resolution * - * On Windows, in Go 1.18.x and earlier, the resolver always used C - * library functions, such as GetAddrInfo and DnsQuery. + * [Timer] resolution varies depending on the Go runtime, the operating system + * and the underlying hardware. + * On Unix, the resolution is ~1ms. + * On Windows version 1803 and newer, the resolution is ~0.5ms. + * On older Windows versions, the default resolution is ~16ms, but + * a higher resolution may be requested using [golang.org/x/sys/windows.TimeBeginPeriod]. */ -namespace net { - /** - * Conn is a generic stream-oriented network connection. - * - * Multiple goroutines may invoke methods on a Conn simultaneously. - */ - interface Conn { - [key:string]: any; +namespace time { + interface Time { /** - * Read reads data from the connection. - * Read can be made to time out and return an error after a fixed - * time limit; see SetDeadline and SetReadDeadline. - */ - read(b: string|Array): number - /** - * Write writes data to the connection. - * Write can be made to time out and return an error after a fixed - * time limit; see SetDeadline and SetWriteDeadline. - */ - write(b: string|Array): number - /** - * Close closes the connection. - * Any blocked Read or Write operations will be unblocked and return errors. - */ - close(): void - /** - * LocalAddr returns the local network address, if known. - */ - localAddr(): Addr - /** - * RemoteAddr returns the remote network address, if known. - */ - remoteAddr(): Addr - /** - * SetDeadline sets the read and write deadlines associated - * with the connection. It is equivalent to calling both - * SetReadDeadline and SetWriteDeadline. - * - * A deadline is an absolute time after which I/O operations - * fail instead of blocking. The deadline applies to all future - * and pending I/O, not just the immediately following call to - * Read or Write. After a deadline has been exceeded, the - * connection can be refreshed by setting a deadline in the future. + * String returns the time formatted using the format string * - * If the deadline is exceeded a call to Read or Write or to other - * I/O methods will return an error that wraps os.ErrDeadlineExceeded. - * This can be tested using errors.Is(err, os.ErrDeadlineExceeded). - * The error's Timeout method will return true, but note that there - * are other possible errors for which the Timeout method will - * return true even if the deadline has not been exceeded. + * ``` + * "2006-01-02 15:04:05.999999999 -0700 MST" + * ``` * - * An idle timeout can be implemented by repeatedly extending - * the deadline after successful Read or Write calls. + * If the time has a monotonic clock reading, the returned string + * includes a final field "m=±", where value is the monotonic + * clock reading formatted as a decimal number of seconds. * - * A zero value for t means I/O operations will not time out. + * The returned string is meant for debugging; for a stable serialized + * representation, use t.MarshalText, t.MarshalBinary, or t.Format + * with an explicit format string. */ - setDeadline(t: time.Time): void + string(): string + } + interface Time { /** - * SetReadDeadline sets the deadline for future Read calls - * and any currently-blocked Read call. - * A zero value for t means Read will not time out. + * GoString implements [fmt.GoStringer] and formats t to be printed in Go source + * code. */ - setReadDeadline(t: time.Time): void + goString(): string + } + interface Time { /** - * SetWriteDeadline sets the deadline for future Write calls - * and any currently-blocked Write call. - * Even if write times out, it may return n > 0, indicating that - * some of the data was successfully written. - * A zero value for t means Write will not time out. + * Format returns a textual representation of the time value formatted according + * to the layout defined by the argument. See the documentation for the + * constant called [Layout] to see how to represent the layout format. + * + * The executable example for [Time.Format] demonstrates the working + * of the layout string in detail and is a good reference. */ - setWriteDeadline(t: time.Time): void + format(layout: string): string + } + interface Time { + /** + * AppendFormat is like [Time.Format] but appends the textual + * representation to b and returns the extended buffer. + */ + appendFormat(b: string|Array, layout: string): string|Array } /** - * A Listener is a generic network listener for stream-oriented protocols. + * A Time represents an instant in time with nanosecond precision. * - * Multiple goroutines may invoke methods on a Listener simultaneously. + * Programs using times should typically store and pass them as values, + * not pointers. That is, time variables and struct fields should be of + * type [time.Time], not *time.Time. + * + * A Time value can be used by multiple goroutines simultaneously except + * that the methods [Time.GobDecode], [Time.UnmarshalBinary], [Time.UnmarshalJSON] and + * [Time.UnmarshalText] are not concurrency-safe. + * + * Time instants can be compared using the [Time.Before], [Time.After], and [Time.Equal] methods. + * The [Time.Sub] method subtracts two instants, producing a [Duration]. + * The [Time.Add] method adds a Time and a Duration, producing a Time. + * + * The zero value of type Time is January 1, year 1, 00:00:00.000000000 UTC. + * As this time is unlikely to come up in practice, the [Time.IsZero] method gives + * a simple way of detecting a time that has not been initialized explicitly. + * + * Each time has an associated [Location]. The methods [Time.Local], [Time.UTC], and Time.In return a + * Time with a specific Location. Changing the Location of a Time value with + * these methods does not change the actual instant it represents, only the time + * zone in which to interpret it. + * + * Representations of a Time value saved by the [Time.GobEncode], [Time.MarshalBinary], [Time.AppendBinary], + * [Time.MarshalJSON], [Time.MarshalText] and [Time.AppendText] methods store the [Time.Location]'s offset, + * but not the location name. They therefore lose information about Daylight Saving Time. + * + * In addition to the required “wall clock” reading, a Time may contain an optional + * reading of the current process's monotonic clock, to provide additional precision + * for comparison or subtraction. + * See the “Monotonic Clocks” section in the package documentation for details. + * + * Note that the Go == operator compares not just the time instant but also the + * Location and the monotonic clock reading. Therefore, Time values should not + * be used as map or database keys without first guaranteeing that the + * identical Location has been set for all values, which can be achieved + * through use of the UTC or Local method, and that the monotonic clock reading + * has been stripped by setting t = t.Round(0). In general, prefer t.Equal(u) + * to t == u, since t.Equal uses the most accurate comparison available and + * correctly handles the case when only one of its arguments has a monotonic + * clock reading. */ - interface Listener { - [key:string]: any; + interface Time { + } + interface Time { /** - * Accept waits for and returns the next connection to the listener. + * IsZero reports whether t represents the zero time instant, + * January 1, year 1, 00:00:00 UTC. */ - accept(): Conn + isZero(): boolean + } + interface Time { /** - * Close closes the listener. - * Any blocked Accept operations will be unblocked and return errors. + * After reports whether the time instant t is after u. */ - close(): void + after(u: Time): boolean + } + interface Time { /** - * Addr returns the listener's network address. + * Before reports whether the time instant t is before u. */ - addr(): Addr + before(u: Time): boolean } -} - -/** - * Package textproto implements generic support for text-based request/response - * protocols in the style of HTTP, NNTP, and SMTP. - * - * The package provides: - * - * [Error], which represents a numeric error response from - * a server. - * - * [Pipeline], to manage pipelined requests and responses - * in a client. - * - * [Reader], to read numeric response code lines, - * key: value headers, lines wrapped with leading spaces - * on continuation lines, and whole text blocks ending - * with a dot on a line by itself. - * - * [Writer], to write dot-encoded text blocks. - * - * [Conn], a convenient packaging of [Reader], [Writer], and [Pipeline] for use - * with a single network connection. - */ -namespace textproto { - /** - * A MIMEHeader represents a MIME-style header mapping - * keys to sets of values. - */ - interface MIMEHeader extends _TygojaDict{} - interface MIMEHeader { + interface Time { /** - * Add adds the key, value pair to the header. - * It appends to any existing values associated with key. + * Compare compares the time instant t with u. If t is before u, it returns -1; + * if t is after u, it returns +1; if they're the same, it returns 0. */ - add(key: string, value: string): void + compare(u: Time): number } - interface MIMEHeader { + interface Time { /** - * Set sets the header entries associated with key to - * the single element value. It replaces any existing - * values associated with key. + * Equal reports whether t and u represent the same time instant. + * Two times can be equal even if they are in different locations. + * For example, 6:00 +0200 and 4:00 UTC are Equal. + * See the documentation on the Time type for the pitfalls of using == with + * Time values; most code should use Equal instead. */ - set(key: string, value: string): void + equal(u: Time): boolean } - interface MIMEHeader { + interface Time { /** - * Get gets the first value associated with the given key. - * It is case insensitive; [CanonicalMIMEHeaderKey] is used - * to canonicalize the provided key. - * If there are no values associated with the key, Get returns "". - * To use non-canonical keys, access the map directly. + * Date returns the year, month, and day in which t occurs. */ - get(key: string): string + date(): [number, Month, number] } - interface MIMEHeader { + interface Time { /** - * Values returns all values associated with the given key. - * It is case insensitive; [CanonicalMIMEHeaderKey] is - * used to canonicalize the provided key. To use non-canonical - * keys, access the map directly. - * The returned slice is not a copy. + * Year returns the year in which t occurs. */ - values(key: string): Array + year(): number } - interface MIMEHeader { + interface Time { /** - * Del deletes the values associated with key. + * Month returns the month of the year specified by t. */ - del(key: string): void + month(): Month } -} - -/** - * Package multipart implements MIME multipart parsing, as defined in RFC - * 2046. - * - * The implementation is sufficient for HTTP (RFC 2388) and the multipart - * bodies generated by popular browsers. - * - * # Limits - * - * To protect against malicious inputs, this package sets limits on the size - * of the MIME data it processes. - * - * [Reader.NextPart] and [Reader.NextRawPart] limit the number of headers in a - * part to 10000 and [Reader.ReadForm] limits the total number of headers in all - * FileHeaders to 10000. - * These limits may be adjusted with the GODEBUG=multipartmaxheaders= - * setting. - * - * Reader.ReadForm further limits the number of parts in a form to 1000. - * This limit may be adjusted with the GODEBUG=multipartmaxparts= - * setting. - */ -namespace multipart { - interface Reader { + interface Time { /** - * ReadForm parses an entire multipart message whose parts have - * a Content-Disposition of "form-data". - * It stores up to maxMemory bytes + 10MB (reserved for non-file parts) - * in memory. File parts which can't be stored in memory will be stored on - * disk in temporary files. - * It returns [ErrMessageTooLarge] if all non-file parts can't be stored in - * memory. + * Day returns the day of the month specified by t. */ - readForm(maxMemory: number): (Form) + day(): number } - /** - * Form is a parsed multipart form. - * Its File parts are stored either in memory or on disk, - * and are accessible via the [*FileHeader]'s Open method. - * Its Value parts are stored as strings. - * Both are keyed by field name. - */ - interface Form { - value: _TygojaDict - file: _TygojaDict - } - interface Form { + interface Time { /** - * RemoveAll removes any temporary files associated with a [Form]. + * Weekday returns the day of the week specified by t. */ - removeAll(): void + weekday(): Weekday } - /** - * File is an interface to access the file part of a multipart message. - * Its contents may be either stored in memory or on disk. - * If stored on disk, the File's underlying concrete type will be an *os.File. - */ - interface File { - [key:string]: any; + interface Time { + /** + * ISOWeek returns the ISO 8601 year and week number in which t occurs. + * Week ranges from 1 to 53. Jan 01 to Jan 03 of year n might belong to + * week 52 or 53 of year n-1, and Dec 29 to Dec 31 might belong to week 1 + * of year n+1. + */ + isoWeek(): [number, number] } - /** - * Reader is an iterator over parts in a MIME multipart body. - * Reader's underlying parser consumes its input as needed. Seeking - * isn't supported. - */ - interface Reader { + interface Time { + /** + * Clock returns the hour, minute, and second within the day specified by t. + */ + clock(): [number, number, number] } - interface Reader { + interface Time { /** - * NextPart returns the next part in the multipart or an error. - * When there are no more parts, the error [io.EOF] is returned. - * - * As a special case, if the "Content-Transfer-Encoding" header - * has a value of "quoted-printable", that header is instead - * hidden and the body is transparently decoded during Read calls. + * Hour returns the hour within the day specified by t, in the range [0, 23]. */ - nextPart(): (Part) + hour(): number } - interface Reader { + interface Time { /** - * NextRawPart returns the next part in the multipart or an error. - * When there are no more parts, the error [io.EOF] is returned. - * - * Unlike [Reader.NextPart], it does not have special handling for - * "Content-Transfer-Encoding: quoted-printable". + * Minute returns the minute offset within the hour specified by t, in the range [0, 59]. */ - nextRawPart(): (Part) + minute(): number } -} - -/** - * Package http provides HTTP client and server implementations. - * - * [Get], [Head], [Post], and [PostForm] make HTTP (or HTTPS) requests: - * - * ``` - * resp, err := http.Get("http://example.com/") - * ... - * resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf) - * ... - * resp, err := http.PostForm("http://example.com/form", - * url.Values{"key": {"Value"}, "id": {"123"}}) - * ``` - * - * The caller must close the response body when finished with it: - * - * ``` - * resp, err := http.Get("http://example.com/") - * if err != nil { - * // handle error - * } - * defer resp.Body.Close() - * body, err := io.ReadAll(resp.Body) - * // ... - * ``` - * - * # Clients and Transports - * - * For control over HTTP client headers, redirect policy, and other - * settings, create a [Client]: - * - * ``` - * client := &http.Client{ - * CheckRedirect: redirectPolicyFunc, - * } - * - * resp, err := client.Get("http://example.com") - * // ... - * - * req, err := http.NewRequest("GET", "http://example.com", nil) - * // ... - * req.Header.Add("If-None-Match", `W/"wyzzy"`) - * resp, err := client.Do(req) - * // ... - * ``` - * - * For control over proxies, TLS configuration, keep-alives, - * compression, and other settings, create a [Transport]: - * - * ``` - * tr := &http.Transport{ - * MaxIdleConns: 10, - * IdleConnTimeout: 30 * time.Second, - * DisableCompression: true, - * } - * client := &http.Client{Transport: tr} - * resp, err := client.Get("https://example.com") - * ``` - * - * Clients and Transports are safe for concurrent use by multiple - * goroutines and for efficiency should only be created once and re-used. - * - * # Servers - * - * ListenAndServe starts an HTTP server with a given address and handler. - * The handler is usually nil, which means to use [DefaultServeMux]. - * [Handle] and [HandleFunc] add handlers to [DefaultServeMux]: - * - * ``` - * http.Handle("/foo", fooHandler) - * - * http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { - * fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) - * }) - * - * log.Fatal(http.ListenAndServe(":8080", nil)) - * ``` - * - * More control over the server's behavior is available by creating a - * custom Server: - * - * ``` - * s := &http.Server{ - * Addr: ":8080", - * Handler: myHandler, - * ReadTimeout: 10 * time.Second, - * WriteTimeout: 10 * time.Second, - * MaxHeaderBytes: 1 << 20, - * } - * log.Fatal(s.ListenAndServe()) - * ``` - * - * # HTTP/2 - * - * Starting with Go 1.6, the http package has transparent support for the - * HTTP/2 protocol when using HTTPS. Programs that must disable HTTP/2 - * can do so by setting [Transport.TLSNextProto] (for clients) or - * [Server.TLSNextProto] (for servers) to a non-nil, empty - * map. Alternatively, the following GODEBUG settings are - * currently supported: - * - * ``` - * GODEBUG=http2client=0 # disable HTTP/2 client support - * GODEBUG=http2server=0 # disable HTTP/2 server support - * GODEBUG=http2debug=1 # enable verbose HTTP/2 debug logs - * GODEBUG=http2debug=2 # ... even more verbose, with frame dumps - * ``` - * - * Please report any issues before disabling HTTP/2 support: https://golang.org/s/http2bug - * - * The http package's [Transport] and [Server] both automatically enable - * HTTP/2 support for simple configurations. To enable HTTP/2 for more - * complex configurations, to use lower-level HTTP/2 features, or to use - * a newer version of Go's http2 package, import "golang.org/x/net/http2" - * directly and use its ConfigureTransport and/or ConfigureServer - * functions. Manually configuring HTTP/2 via the golang.org/x/net/http2 - * package takes precedence over the net/http package's built-in HTTP/2 - * support. - */ -namespace http { - /** - * A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an - * HTTP response or the Cookie header of an HTTP request. - * - * See https://tools.ietf.org/html/rfc6265 for details. - */ - interface Cookie { - name: string - value: string - quoted: boolean // indicates whether the Value was originally quoted - path: string // optional - domain: string // optional - expires: time.Time // optional - rawExpires: string // for reading cookies only + interface Time { /** - * MaxAge=0 means no 'Max-Age' attribute specified. - * MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' - * MaxAge>0 means Max-Age attribute present and given in seconds + * Second returns the second offset within the minute specified by t, in the range [0, 59]. */ - maxAge: number - secure: boolean - httpOnly: boolean - sameSite: SameSite - partitioned: boolean - raw: string - unparsed: Array // Raw text of unparsed attribute-value pairs + second(): number } - interface Cookie { + interface Time { /** - * String returns the serialization of the cookie for use in a [Cookie] - * header (if only Name and Value are set) or a Set-Cookie response - * header (if other fields are set). - * If c is nil or c.Name is invalid, the empty string is returned. + * Nanosecond returns the nanosecond offset within the second specified by t, + * in the range [0, 999999999]. */ - string(): string + nanosecond(): number } - interface Cookie { + interface Time { /** - * Valid reports whether the cookie is valid. + * YearDay returns the day of the year specified by t, in the range [1,365] for non-leap years, + * and [1,366] in leap years. */ - valid(): void + yearDay(): number } - // @ts-ignore - import mathrand = rand /** - * A Header represents the key-value pairs in an HTTP header. - * - * The keys should be in canonical form, as returned by - * [CanonicalHeaderKey]. + * A Duration represents the elapsed time between two instants + * as an int64 nanosecond count. The representation limits the + * largest representable duration to approximately 290 years. */ - interface Header extends _TygojaDict{} - interface Header { + interface Duration extends Number{} + interface Duration { /** - * Add adds the key, value pair to the header. - * It appends to any existing values associated with key. - * The key is case insensitive; it is canonicalized by - * [CanonicalHeaderKey]. + * String returns a string representing the duration in the form "72h3m0.5s". + * Leading zero units are omitted. As a special case, durations less than one + * second format use a smaller unit (milli-, micro-, or nanoseconds) to ensure + * that the leading digit is non-zero. The zero duration formats as 0s. */ - add(key: string, value: string): void + string(): string } - interface Header { + interface Duration { /** - * Set sets the header entries associated with key to the - * single element value. It replaces any existing values - * associated with key. The key is case insensitive; it is - * canonicalized by [textproto.CanonicalMIMEHeaderKey]. - * To use non-canonical keys, assign to the map directly. + * Nanoseconds returns the duration as an integer nanosecond count. */ - set(key: string, value: string): void + nanoseconds(): number } - interface Header { + interface Duration { /** - * Get gets the first value associated with the given key. If - * there are no values associated with the key, Get returns "". - * It is case insensitive; [textproto.CanonicalMIMEHeaderKey] is - * used to canonicalize the provided key. Get assumes that all - * keys are stored in canonical form. To use non-canonical keys, - * access the map directly. + * Microseconds returns the duration as an integer microsecond count. */ - get(key: string): string + microseconds(): number } - interface Header { + interface Duration { /** - * Values returns all values associated with the given key. - * It is case insensitive; [textproto.CanonicalMIMEHeaderKey] is - * used to canonicalize the provided key. To use non-canonical - * keys, access the map directly. - * The returned slice is not a copy. + * Milliseconds returns the duration as an integer millisecond count. */ - values(key: string): Array + milliseconds(): number } - interface Header { + interface Duration { /** - * Del deletes the values associated with key. - * The key is case insensitive; it is canonicalized by - * [CanonicalHeaderKey]. + * Seconds returns the duration as a floating point number of seconds. */ - del(key: string): void + seconds(): number } - interface Header { + interface Duration { /** - * Write writes a header in wire format. + * Minutes returns the duration as a floating point number of minutes. */ - write(w: io.Writer): void + minutes(): number } - interface Header { + interface Duration { /** - * Clone returns a copy of h or nil if h is nil. + * Hours returns the duration as a floating point number of hours. */ - clone(): Header + hours(): number } - interface Header { + interface Duration { /** - * WriteSubset writes a header in wire format. - * If exclude is not nil, keys where exclude[key] == true are not written. - * Keys are not canonicalized before checking the exclude map. + * Truncate returns the result of rounding d toward zero to a multiple of m. + * If m <= 0, Truncate returns d unchanged. */ - writeSubset(w: io.Writer, exclude: _TygojaDict): void + truncate(m: Duration): Duration } - // @ts-ignore - import urlpkg = url - /** - * Response represents the response from an HTTP request. - * - * The [Client] and [Transport] return Responses from servers once - * the response headers have been received. The response body - * is streamed on demand as the Body field is read. - */ - interface Response { - status: string // e.g. "200 OK" - statusCode: number // e.g. 200 - proto: string // e.g. "HTTP/1.0" - protoMajor: number // e.g. 1 - protoMinor: number // e.g. 0 + interface Duration { /** - * Header maps header keys to values. If the response had multiple - * headers with the same key, they may be concatenated, with comma - * delimiters. (RFC 7230, section 3.2.2 requires that multiple headers - * be semantically equivalent to a comma-delimited sequence.) When - * Header values are duplicated by other fields in this struct (e.g., - * ContentLength, TransferEncoding, Trailer), the field values are - * authoritative. - * - * Keys in the map are canonicalized (see CanonicalHeaderKey). + * Round returns the result of rounding d to the nearest multiple of m. + * The rounding behavior for halfway values is to round away from zero. + * If the result exceeds the maximum (or minimum) + * value that can be stored in a [Duration], + * Round returns the maximum (or minimum) duration. + * If m <= 0, Round returns d unchanged. */ - header: Header + round(m: Duration): Duration + } + interface Duration { /** - * Body represents the response body. - * - * The response body is streamed on demand as the Body field - * is read. If the network connection fails or the server - * terminates the response, Body.Read calls return an error. - * - * The http Client and Transport guarantee that Body is always - * non-nil, even on responses without a body or responses with - * a zero-length body. It is the caller's responsibility to - * close Body. The default HTTP client's Transport may not - * reuse HTTP/1.x "keep-alive" TCP connections if the Body is - * not read to completion and closed. - * - * The Body is automatically dechunked if the server replied - * with a "chunked" Transfer-Encoding. - * - * As of Go 1.12, the Body will also implement io.Writer - * on a successful "101 Switching Protocols" response, - * as used by WebSockets and HTTP/2's "h2c" mode. + * Abs returns the absolute value of d. + * As a special case, Duration([math.MinInt64]) is converted to Duration([math.MaxInt64]), + * reducing its magnitude by 1 nanosecond. */ - body: io.ReadCloser + abs(): Duration + } + interface Time { /** - * ContentLength records the length of the associated content. The - * value -1 indicates that the length is unknown. Unless Request.Method - * is "HEAD", values >= 0 indicate that the given number of bytes may - * be read from Body. + * Add returns the time t+d. */ - contentLength: number + add(d: Duration): Time + } + interface Time { /** - * Contains transfer encodings from outer-most to inner-most. Value is - * nil, means that "identity" encoding is used. + * Sub returns the duration t-u. If the result exceeds the maximum (or minimum) + * value that can be stored in a [Duration], the maximum (or minimum) duration + * will be returned. + * To compute t-d for a duration d, use t.Add(-d). */ - transferEncoding: Array + sub(u: Time): Duration + } + interface Time { /** - * Close records whether the header directed that the connection be - * closed after reading Body. The value is advice for clients: neither - * ReadResponse nor Response.Write ever closes a connection. + * AddDate returns the time corresponding to adding the + * given number of years, months, and days to t. + * For example, AddDate(-1, 2, 3) applied to January 1, 2011 + * returns March 4, 2010. + * + * Note that dates are fundamentally coupled to timezones, and calendrical + * periods like days don't have fixed durations. AddDate uses the Location of + * the Time value to determine these durations. That means that the same + * AddDate arguments can produce a different shift in absolute time depending on + * the base Time value and its Location. For example, AddDate(0, 0, 1) applied + * to 12:00 on March 27 always returns 12:00 on March 28. At some locations and + * in some years this is a 24 hour shift. In others it's a 23 hour shift due to + * daylight savings time transitions. + * + * AddDate normalizes its result in the same way that Date does, + * so, for example, adding one month to October 31 yields + * December 1, the normalized form for November 31. */ - close: boolean + addDate(years: number, months: number, days: number): Time + } + interface Time { /** - * Uncompressed reports whether the response was sent compressed but - * was decompressed by the http package. When true, reading from - * Body yields the uncompressed content instead of the compressed - * content actually set from the server, ContentLength is set to -1, - * and the "Content-Length" and "Content-Encoding" fields are deleted - * from the responseHeader. To get the original response from - * the server, set Transport.DisableCompression to true. + * UTC returns t with the location set to UTC. */ - uncompressed: boolean + utc(): Time + } + interface Time { /** - * Trailer maps trailer keys to values in the same - * format as Header. - * - * The Trailer initially contains only nil values, one for - * each key specified in the server's "Trailer" header - * value. Those values are not added to Header. - * - * Trailer must not be accessed concurrently with Read calls - * on the Body. + * Local returns t with the location set to local time. + */ + local(): Time + } + interface Time { + /** + * In returns a copy of t representing the same time instant, but + * with the copy's location information set to loc for display + * purposes. * - * After Body.Read has returned io.EOF, Trailer will contain - * any trailer values sent by the server. + * In panics if loc is nil. */ - trailer: Header + in(loc: Location): Time + } + interface Time { /** - * Request is the request that was sent to obtain this Response. - * Request's Body is nil (having already been consumed). - * This is only populated for Client requests. + * Location returns the time zone information associated with t. */ - request?: Request + location(): (Location) + } + interface Time { /** - * TLS contains information about the TLS connection on which the - * response was received. It is nil for unencrypted responses. - * The pointer is shared between responses and should not be - * modified. + * Zone computes the time zone in effect at time t, returning the abbreviated + * name of the zone (such as "CET") and its offset in seconds east of UTC. */ - tls?: any + zone(): [string, number] } - interface Response { + interface Time { /** - * Cookies parses and returns the cookies set in the Set-Cookie headers. + * ZoneBounds returns the bounds of the time zone in effect at time t. + * The zone begins at start and the next zone begins at end. + * If the zone begins at the beginning of time, start will be returned as a zero Time. + * If the zone goes on forever, end will be returned as a zero Time. + * The Location of the returned times will be the same as t. */ - cookies(): Array<(Cookie | undefined)> + zoneBounds(): [Time, Time] } - interface Response { + interface Time { /** - * Location returns the URL of the response's "Location" header, - * if present. Relative redirects are resolved relative to - * [Response.Request]. [ErrNoLocation] is returned if no - * Location header is present. + * Unix returns t as a Unix time, the number of seconds elapsed + * since January 1, 1970 UTC. The result does not depend on the + * location associated with t. + * Unix-like operating systems often record time as a 32-bit + * count of seconds, but since the method here returns a 64-bit + * value it is valid for billions of years into the past or future. */ - location(): (url.URL) + unix(): number } - interface Response { + interface Time { /** - * ProtoAtLeast reports whether the HTTP protocol used - * in the response is at least major.minor. + * UnixMilli returns t as a Unix time, the number of milliseconds elapsed since + * January 1, 1970 UTC. The result is undefined if the Unix time in + * milliseconds cannot be represented by an int64 (a date more than 292 million + * years before or after 1970). The result does not depend on the + * location associated with t. */ - protoAtLeast(major: number, minor: number): boolean + unixMilli(): number } - interface Response { + interface Time { /** - * Write writes r to w in the HTTP/1.x server response format, - * including the status line, headers, body, and optional trailer. - * - * This method consults the following fields of the response r: - * - * ``` - * StatusCode - * ProtoMajor - * ProtoMinor - * Request.Method - * TransferEncoding - * Trailer - * Body - * ContentLength - * Header, values for non-canonical keys will have unpredictable behavior - * ``` - * - * The Response Body is closed after it is sent. + * UnixMicro returns t as a Unix time, the number of microseconds elapsed since + * January 1, 1970 UTC. The result is undefined if the Unix time in + * microseconds cannot be represented by an int64 (a date before year -290307 or + * after year 294246). The result does not depend on the location associated + * with t. */ - write(w: io.Writer): void - } - /** - * A Handler responds to an HTTP request. - * - * [Handler.ServeHTTP] should write reply headers and data to the [ResponseWriter] - * and then return. Returning signals that the request is finished; it - * is not valid to use the [ResponseWriter] or read from the - * [Request.Body] after or concurrently with the completion of the - * ServeHTTP call. - * - * Depending on the HTTP client software, HTTP protocol version, and - * any intermediaries between the client and the Go server, it may not - * be possible to read from the [Request.Body] after writing to the - * [ResponseWriter]. Cautious handlers should read the [Request.Body] - * first, and then reply. - * - * Except for reading the body, handlers should not modify the - * provided Request. - * - * If ServeHTTP panics, the server (the caller of ServeHTTP) assumes - * that the effect of the panic was isolated to the active request. - * It recovers the panic, logs a stack trace to the server error log, - * and either closes the network connection or sends an HTTP/2 - * RST_STREAM, depending on the HTTP protocol. To abort a handler so - * the client sees an interrupted response but the server doesn't log - * an error, panic with the value [ErrAbortHandler]. - */ - interface Handler { - [key:string]: any; - serveHTTP(_arg0: ResponseWriter, _arg1: Request): void - } - /** - * A ConnState represents the state of a client connection to a server. - * It's used by the optional [Server.ConnState] hook. - */ - interface ConnState extends Number{} - interface ConnState { - string(): string - } -} - -/** - * Package oauth2 provides support for making - * OAuth2 authorized and authenticated HTTP requests, - * as specified in RFC 6749. - * It can additionally grant authorization with Bearer JWT. - */ -/** - * Copyright 2023 The Go Authors. All rights reserved. - * Use of this source code is governed by a BSD-style - * license that can be found in the LICENSE file. - */ -namespace oauth2 { - /** - * An AuthCodeOption is passed to Config.AuthCodeURL. - */ - interface AuthCodeOption { - [key:string]: any; + unixMicro(): number } - /** - * Token represents the credentials used to authorize - * the requests to access protected resources on the OAuth 2.0 - * provider's backend. - * - * Most users of this package should not access fields of Token - * directly. They're exported mostly for use by related packages - * implementing derivative OAuth2 flows. - */ - interface Token { - /** - * AccessToken is the token that authorizes and authenticates - * the requests. - */ - accessToken: string - /** - * TokenType is the type of token. - * The Type method returns either this or "Bearer", the default. - */ - tokenType: string - /** - * RefreshToken is a token that's used by the application - * (as opposed to the user) to refresh the access token - * if it expires. - */ - refreshToken: string - /** - * Expiry is the optional expiration time of the access token. - * - * If zero, TokenSource implementations will reuse the same - * token forever and RefreshToken or equivalent - * mechanisms for that TokenSource will not be used. - */ - expiry: time.Time + interface Time { /** - * ExpiresIn is the OAuth2 wire format "expires_in" field, - * which specifies how many seconds later the token expires, - * relative to an unknown time base approximately around "now". - * It is the application's responsibility to populate - * `Expiry` from `ExpiresIn` when required. + * UnixNano returns t as a Unix time, the number of nanoseconds elapsed + * since January 1, 1970 UTC. The result is undefined if the Unix time + * in nanoseconds cannot be represented by an int64 (a date before the year + * 1678 or after 2262). Note that this means the result of calling UnixNano + * on the zero Time is undefined. The result does not depend on the + * location associated with t. */ - expiresIn: number + unixNano(): number } - interface Token { + interface Time { /** - * Type returns t.TokenType if non-empty, else "Bearer". + * AppendBinary implements the [encoding.BinaryAppender] interface. */ - type(): string + appendBinary(b: string|Array): string|Array } - interface Token { + interface Time { /** - * SetAuthHeader sets the Authorization header to r using the access - * token in t. - * - * This method is unnecessary when using Transport or an HTTP Client - * returned by this package. + * MarshalBinary implements the [encoding.BinaryMarshaler] interface. */ - setAuthHeader(r: http.Request): void + marshalBinary(): string|Array } - interface Token { + interface Time { /** - * WithExtra returns a new Token that's a clone of t, but using the - * provided raw extra map. This is only intended for use by packages - * implementing derivative OAuth2 flows. + * UnmarshalBinary implements the [encoding.BinaryUnmarshaler] interface. */ - withExtra(extra: { - }): (Token) + unmarshalBinary(data: string|Array): void } - interface Token { + interface Time { /** - * Extra returns an extra field. - * Extra fields are key-value pairs returned by the server as a - * part of the token retrieval response. + * GobEncode implements the gob.GobEncoder interface. */ - extra(key: string): { - } + gobEncode(): string|Array } - interface Token { + interface Time { /** - * Valid reports whether t is non-nil, has an AccessToken, and is not expired. + * GobDecode implements the gob.GobDecoder interface. */ - valid(): boolean - } -} - -namespace store { - /** - * Store defines a concurrent safe in memory key-value data store. - */ - interface Store { + gobDecode(data: string|Array): void } - interface Store { + interface Time { /** - * Reset clears the store and replaces the store data with a - * shallow copy of the provided newData. + * MarshalJSON implements the [encoding/json.Marshaler] interface. + * The time is a quoted string in the RFC 3339 format with sub-second precision. + * If the timestamp cannot be represented as valid RFC 3339 + * (e.g., the year is out of range), then an error is reported. */ - reset(newData: _TygojaDict): void + marshalJSON(): string|Array } - interface Store { + interface Time { /** - * Length returns the current number of elements in the store. + * UnmarshalJSON implements the [encoding/json.Unmarshaler] interface. + * The time must be a quoted string in the RFC 3339 format. */ - length(): number + unmarshalJSON(data: string|Array): void } - interface Store { + interface Time { /** - * RemoveAll removes all the existing store entries. + * AppendText implements the [encoding.TextAppender] interface. + * The time is formatted in RFC 3339 format with sub-second precision. + * If the timestamp cannot be represented as valid RFC 3339 + * (e.g., the year is out of range), then an error is returned. */ - removeAll(): void + appendText(b: string|Array): string|Array } - interface Store { + interface Time { /** - * Remove removes a single entry from the store. + * MarshalText implements the [encoding.TextMarshaler] interface. The output + * matches that of calling the [Time.AppendText] method. * - * Remove does nothing if key doesn't exist in the store. - */ - remove(key: string): void - } - interface Store { - /** - * Has checks if element with the specified key exist or not. + * See [Time.AppendText] for more information. */ - has(key: string): boolean + marshalText(): string|Array } - interface Store { + interface Time { /** - * Get returns a single element value from the store. - * - * If key is not set, the zero T value is returned. + * UnmarshalText implements the [encoding.TextUnmarshaler] interface. + * The time must be in the RFC 3339 format. */ - get(key: string): T + unmarshalText(data: string|Array): void } - interface Store { + interface Time { /** - * GetAll returns a shallow copy of the current store data. + * IsDST reports whether the time in the configured location is in Daylight Savings Time. */ - getAll(): _TygojaDict + isDST(): boolean } - interface Store { + interface Time { /** - * Set sets (or overwrite if already exist) a new value for key. + * Truncate returns the result of rounding t down to a multiple of d (since the zero time). + * If d <= 0, Truncate returns t stripped of any monotonic clock reading but otherwise unchanged. + * + * Truncate operates on the time as an absolute duration since the + * zero time; it does not operate on the presentation form of the + * time. Thus, Truncate(Hour) may return a time with a non-zero + * minute, depending on the time's Location. */ - set(key: string, value: T): void + truncate(d: Duration): Time } - interface Store { + interface Time { /** - * SetIfLessThanLimit sets (or overwrite if already exist) a new value for key. + * Round returns the result of rounding t to the nearest multiple of d (since the zero time). + * The rounding behavior for halfway values is to round up. + * If d <= 0, Round returns t stripped of any monotonic clock reading but otherwise unchanged. * - * This method is similar to Set() but **it will skip adding new elements** - * to the store if the store length has reached the specified limit. - * false is returned if maxAllowedElements limit is reached. + * Round operates on the time as an absolute duration since the + * zero time; it does not operate on the presentation form of the + * time. Thus, Round(Hour) may return a time with a non-zero + * minute, depending on the time's Location. */ - setIfLessThanLimit(key: string, value: T, maxAllowedElements: number): boolean + round(d: Duration): Time } } -namespace mailer { +/** + * Package fs defines basic interfaces to a file system. + * A file system can be provided by the host operating system + * but also by other packages. + * + * See the [testing/fstest] package for support with testing + * implementations of file systems. + */ +namespace fs { /** - * Mailer defines a base mail client interface. + * An FS provides access to a hierarchical file system. + * + * The FS interface is the minimum implementation required of the file system. + * A file system may implement additional interfaces, + * such as [ReadFileFS], to provide additional or optimized functionality. + * + * [testing/fstest.TestFS] may be used to test implementations of an FS for + * correctness. */ - interface Mailer { + interface FS { [key:string]: any; /** - * Send sends an email with the provided Message. + * Open opens the named file. + * [File.Close] must be called to release any associated resources. + * + * When Open returns an error, it should be of type *PathError + * with the Op field set to "open", the Path field set to name, + * and the Err field describing the problem. + * + * Open should reject attempts to open names that do not satisfy + * ValidPath(name), returning a *PathError with Err set to + * ErrInvalid or ErrNotExist. */ - send(message: Message): void + open(name: string): File } -} - -/** - * Package echo implements high performance, minimalist Go web framework. - * - * Example: - * - * ``` - * package main - * - * import ( - * "github.com/labstack/echo/v5" - * "github.com/labstack/echo/v5/middleware" - * "log" - * "net/http" - * ) - * - * // Handler - * func hello(c echo.Context) error { - * return c.String(http.StatusOK, "Hello, World!") - * } - * - * func main() { - * // Echo instance - * e := echo.New() - * - * // Middleware - * e.Use(middleware.Logger()) - * e.Use(middleware.Recover()) - * - * // Routes - * e.GET("/", hello) - * - * // Start server - * if err := e.Start(":8080"); err != http.ErrServerClosed { - * log.Fatal(err) - * } - * } - * ``` - * - * Learn more at https://echo.labstack.com - */ -namespace echo { /** - * Binder is the interface that wraps the Bind method. + * A File provides access to a single file. + * The File interface is the minimum implementation required of the file. + * Directory files should also implement [ReadDirFile]. + * A file may implement [io.ReaderAt] or [io.Seeker] as optimizations. */ - interface Binder { + interface File { [key:string]: any; - bind(c: Context, i: { - }): void + stat(): FileInfo + read(_arg0: string|Array): number + close(): void } /** - * ServableContext is interface that Echo context implementation must implement to be usable in middleware/handlers and - * be able to be routed by Router. + * A DirEntry is an entry read from a directory + * (using the [ReadDir] function or a [ReadDirFile]'s ReadDir method). */ - interface ServableContext { + interface DirEntry { [key:string]: any; /** - * Reset resets the context after request completes. It must be called along - * with `Echo#AcquireContext()` and `Echo#ReleaseContext()`. - * See `Echo#ServeHTTP()` + * Name returns the name of the file (or subdirectory) described by the entry. + * This name is only the final element of the path (the base name), not the entire path. + * For example, Name would return "hello.go" not "home/gopher/hello.go". */ - reset(r: http.Request, w: http.ResponseWriter): void - } - // @ts-ignore - import stdContext = context - /** - * JSONSerializer is the interface that encodes and decodes JSON to and from interfaces. - */ - interface JSONSerializer { - [key:string]: any; - serialize(c: Context, i: { - }, indent: string): void - deserialize(c: Context, i: { - }): void - } - /** - * HTTPErrorHandler is a centralized HTTP error handler. - */ - interface HTTPErrorHandler {(c: Context, err: Error): void } - /** - * Validator is the interface that wraps the Validate function. - */ - interface Validator { - [key:string]: any; - validate(i: { - }): void + name(): string + /** + * IsDir reports whether the entry describes a directory. + */ + isDir(): boolean + /** + * Type returns the type bits for the entry. + * The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method. + */ + type(): FileMode + /** + * Info returns the FileInfo for the file or subdirectory described by the entry. + * The returned FileInfo may be from the time of the original directory read + * or from the time of the call to Info. If the file has been removed or renamed + * since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist). + * If the entry denotes a symbolic link, Info reports the information about the link itself, + * not the link's target. + */ + info(): FileInfo } /** - * Renderer is the interface that wraps the Render function. + * A FileInfo describes a file and is returned by [Stat]. */ - interface Renderer { + interface FileInfo { [key:string]: any; - render(_arg0: io.Writer, _arg1: string, _arg2: { - }, _arg3: Context): void + name(): string // base name of the file + size(): number // length in bytes for regular files; system-dependent for others + mode(): FileMode // file mode bits + modTime(): time.Time // modification time + isDir(): boolean // abbreviation for Mode().IsDir() + sys(): any // underlying data source (can return nil) } /** - * Group is a set of sub-routes for a specified route. It can be used for inner - * routes that share a common middleware or functionality that should be separate - * from the parent echo instance while still inheriting from it. + * A FileMode represents a file's mode and permission bits. + * The bits have the same definition on all systems, so that + * information about files can be moved from one system + * to another portably. Not all bits apply to all systems. + * The only required bit is [ModeDir] for directories. */ - interface Group { - } - interface Group { - /** - * Use implements `Echo#Use()` for sub-routes within the Group. - * Group middlewares are not executed on request when there is no matching route found. - */ - use(...middleware: MiddlewareFunc[]): void - } - interface Group { - /** - * CONNECT implements `Echo#CONNECT()` for sub-routes within the Group. Panics on error. - */ - connect(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + interface FileMode extends Number{} + interface FileMode { + string(): string } - interface Group { + interface FileMode { /** - * DELETE implements `Echo#DELETE()` for sub-routes within the Group. Panics on error. + * IsDir reports whether m describes a directory. + * That is, it tests for the [ModeDir] bit being set in m. */ - delete(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + isDir(): boolean } - interface Group { + interface FileMode { /** - * GET implements `Echo#GET()` for sub-routes within the Group. Panics on error. + * IsRegular reports whether m describes a regular file. + * That is, it tests that no mode type bits are set. */ - get(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + isRegular(): boolean } - interface Group { + interface FileMode { /** - * HEAD implements `Echo#HEAD()` for sub-routes within the Group. Panics on error. + * Perm returns the Unix permission bits in m (m & [ModePerm]). */ - head(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + perm(): FileMode } - interface Group { + interface FileMode { /** - * OPTIONS implements `Echo#OPTIONS()` for sub-routes within the Group. Panics on error. + * Type returns type bits in m (m & [ModeType]). */ - options(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + type(): FileMode } - interface Group { - /** - * PATCH implements `Echo#PATCH()` for sub-routes within the Group. Panics on error. - */ - patch(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + /** + * PathError records an error and the operation and file path that caused it. + */ + interface PathError { + op: string + path: string + err: Error } - interface Group { - /** - * POST implements `Echo#POST()` for sub-routes within the Group. Panics on error. - */ - post(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + interface PathError { + error(): string } - interface Group { - /** - * PUT implements `Echo#PUT()` for sub-routes within the Group. Panics on error. - */ - put(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + interface PathError { + unwrap(): void } - interface Group { + interface PathError { /** - * TRACE implements `Echo#TRACE()` for sub-routes within the Group. Panics on error. + * Timeout reports whether this error represents a timeout. */ - trace(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + timeout(): boolean } - interface Group { - /** - * Any implements `Echo#Any()` for sub-routes within the Group. Panics on error. - */ - any(path: string, handler: HandlerFunc, ...middleware: MiddlewareFunc[]): Routes + /** + * WalkDirFunc is the type of the function called by [WalkDir] to visit + * each file or directory. + * + * The path argument contains the argument to [WalkDir] as a prefix. + * That is, if WalkDir is called with root argument "dir" and finds a file + * named "a" in that directory, the walk function will be called with + * argument "dir/a". + * + * The d argument is the [DirEntry] for the named path. + * + * The error result returned by the function controls how [WalkDir] + * continues. If the function returns the special value [SkipDir], WalkDir + * skips the current directory (path if d.IsDir() is true, otherwise + * path's parent directory). If the function returns the special value + * [SkipAll], WalkDir skips all remaining files and directories. Otherwise, + * if the function returns a non-nil error, WalkDir stops entirely and + * returns that error. + * + * The err argument reports an error related to path, signaling that + * [WalkDir] will not walk into that directory. The function can decide how + * to handle that error; as described earlier, returning the error will + * cause WalkDir to stop walking the entire tree. + * + * [WalkDir] calls the function with a non-nil err argument in two cases. + * + * First, if the initial [Stat] on the root directory fails, WalkDir + * calls the function with path set to root, d set to nil, and err set to + * the error from [fs.Stat]. + * + * Second, if a directory's ReadDir method (see [ReadDirFile]) fails, WalkDir calls the + * function with path set to the directory's path, d set to an + * [DirEntry] describing the directory, and err set to the error from + * ReadDir. In this second case, the function is called twice with the + * path of the directory: the first call is before the directory read is + * attempted and has err set to nil, giving the function a chance to + * return [SkipDir] or [SkipAll] and avoid the ReadDir entirely. The second call + * is after a failed ReadDir and reports the error from ReadDir. + * (If ReadDir succeeds, there is no second call.) + * + * The differences between WalkDirFunc compared to [path/filepath.WalkFunc] are: + * + * ``` + * - The second argument has type [DirEntry] instead of [FileInfo]. + * - The function is called before reading a directory, to allow [SkipDir] + * or [SkipAll] to bypass the directory read entirely or skip all remaining + * files and directories respectively. + * - If a directory read fails, the function is called a second time + * for that directory to report the error. + * ``` + */ + interface WalkDirFunc {(path: string, d: DirEntry, err: Error): void } +} + +namespace store { + /** + * Store defines a concurrent safe in memory key-value data store. + */ + interface Store { } - interface Group { + interface Store { /** - * Match implements `Echo#Match()` for sub-routes within the Group. Panics on error. + * Reset clears the store and replaces the store data with a + * shallow copy of the provided newData. */ - match(methods: Array, path: string, handler: HandlerFunc, ...middleware: MiddlewareFunc[]): Routes + reset(newData: _TygojaDict): void } - interface Group { + interface Store { /** - * Group creates a new sub-group with prefix and optional sub-group-level middleware. - * Important! Group middlewares are only executed in case there was exact route match and not - * for 404 (not found) or 405 (method not allowed) cases. If this kind of behaviour is needed then add - * a catch-all route `/*` for the group which handler returns always 404 + * Length returns the current number of elements in the store. */ - group(prefix: string, ...middleware: MiddlewareFunc[]): (Group) + length(): number } - interface Group { + interface Store { /** - * Static implements `Echo#Static()` for sub-routes within the Group. + * RemoveAll removes all the existing store entries. */ - static(pathPrefix: string, fsRoot: string): RouteInfo + removeAll(): void } - interface Group { + interface Store { /** - * StaticFS implements `Echo#StaticFS()` for sub-routes within the Group. + * Remove removes a single entry from the store. * - * When dealing with `embed.FS` use `fs := echo.MustSubFS(fs, "rootDirectory") to create sub fs which uses necessary - * prefix for directory path. This is necessary as `//go:embed assets/images` embeds files with paths - * including `assets/images` as their prefix. - */ - staticFS(pathPrefix: string, filesystem: fs.FS): RouteInfo - } - interface Group { - /** - * FileFS implements `Echo#FileFS()` for sub-routes within the Group. + * Remove does nothing if key doesn't exist in the store. */ - fileFS(path: string, file: string, filesystem: fs.FS, ...m: MiddlewareFunc[]): RouteInfo + remove(key: K): void } - interface Group { + interface Store { /** - * File implements `Echo#File()` for sub-routes within the Group. Panics on error. + * Has checks if element with the specified key exist or not. */ - file(path: string, file: string, ...middleware: MiddlewareFunc[]): RouteInfo + has(key: K): boolean } - interface Group { + interface Store { /** - * RouteNotFound implements `Echo#RouteNotFound()` for sub-routes within the Group. + * Get returns a single element value from the store. * - * Example: `g.RouteNotFound("/*", func(c echo.Context) error { return c.NoContent(http.StatusNotFound) })` + * If key is not set, the zero T value is returned. */ - routeNotFound(path: string, h: HandlerFunc, ...m: MiddlewareFunc[]): RouteInfo + get(key: K): T } - interface Group { + interface Store { /** - * Add implements `Echo#Add()` for sub-routes within the Group. Panics on error. + * GetOk is similar to Get but returns also a boolean indicating whether the key exists or not. */ - add(method: string, path: string, handler: HandlerFunc, ...middleware: MiddlewareFunc[]): RouteInfo + getOk(key: K): [T, boolean] } - interface Group { + interface Store { /** - * AddRoute registers a new Routable with Router + * GetAll returns a shallow copy of the current store data. */ - addRoute(route: Routable): RouteInfo + getAll(): _TygojaDict } - /** - * IPExtractor is a function to extract IP addr from http.Request. - * Set appropriate one to Echo#IPExtractor. - * See https://echo.labstack.com/guide/ip-address for more details. - */ - interface IPExtractor {(_arg0: http.Request): string } - /** - * Logger defines the logging interface that Echo uses internally in few places. - * For logging in handlers use your own logger instance (dependency injected or package/public variable) from logging framework of your choice. - */ - interface Logger { - [key:string]: any; - /** - * Write provides writer interface for http.Server `ErrorLog` and for logging startup messages. - * `http.Server.ErrorLog` logs errors from accepting connections, unexpected behavior from handlers, - * and underlying FileSystem errors. - * `logger` middleware will use this method to write its JSON payload. - */ - write(p: string|Array): number + interface Store { /** - * Error logs the error + * Values returns a slice with all of the current store values. */ - error(err: Error): void - } - /** - * Response wraps an http.ResponseWriter and implements its interface to be used - * by an HTTP handler to construct an HTTP response. - * See: https://golang.org/pkg/net/http/#ResponseWriter - */ - interface Response { - writer: http.ResponseWriter - status: number - size: number - committed: boolean + values(): Array } - interface Response { + interface Store { /** - * Header returns the header map for the writer that will be sent by - * WriteHeader. Changing the header after a call to WriteHeader (or Write) has - * no effect unless the modified headers were declared as trailers by setting - * the "Trailer" header before the call to WriteHeader (see example) - * To suppress implicit response headers, set their value to nil. - * Example: https://golang.org/pkg/net/http/#example_ResponseWriter_trailers + * Set sets (or overwrite if already exists) a new value for key. */ - header(): http.Header + set(key: K, value: T): void } - interface Response { + interface Store { /** - * Before registers a function which is called just before the response is written. + * SetFunc sets (or overwrite if already exists) a new value resolved + * from the function callback for the provided key. + * + * The function callback receives as argument the old store element value (if exists). + * If there is no old store element, the argument will be the T zero value. + * + * Example: + * + * ``` + * s := store.New[string, int](nil) + * s.SetFunc("count", func(old int) int { + * return old + 1 + * }) + * ``` */ - before(fn: () => void): void + setFunc(key: K, fn: (old: T) => T): void } - interface Response { + interface Store { /** - * After registers a function which is called just after the response is written. - * If the `Content-Length` is unknown, none of the after function is executed. + * GetOrSet retrieves a single existing value for the provided key + * or stores a new one if it doesn't exist. */ - after(fn: () => void): void + getOrSet(key: K, setFunc: () => T): T } - interface Response { + interface Store { /** - * WriteHeader sends an HTTP response header with status code. If WriteHeader is - * not called explicitly, the first call to Write will trigger an implicit - * WriteHeader(http.StatusOK). Thus explicit calls to WriteHeader are mainly - * used to send error codes. + * SetIfLessThanLimit sets (or overwrite if already exist) a new value for key. + * + * This method is similar to Set() but **it will skip adding new elements** + * to the store if the store length has reached the specified limit. + * false is returned if maxAllowedElements limit is reached. */ - writeHeader(code: number): void + setIfLessThanLimit(key: K, value: T, maxAllowedElements: number): boolean } - interface Response { + interface Store { /** - * Write writes the data to the connection as part of an HTTP reply. + * UnmarshalJSON implements [json.Unmarshaler] and imports the + * provided JSON data into the store. + * + * The store entries that match with the ones from the data will be overwritten with the new value. */ - write(b: string|Array): number + unmarshalJSON(data: string|Array): void } - interface Response { + interface Store { /** - * Flush implements the http.Flusher interface to allow an HTTP handler to flush - * buffered data to the client. - * See [http.Flusher](https://golang.org/pkg/net/http/#Flusher) + * MarshalJSON implements [json.Marshaler] and export the current + * store data into valid JSON. */ - flush(): void - } - interface Response { - /** - * Hijack implements the http.Hijacker interface to allow an HTTP handler to - * take over the connection. - * See [http.Hijacker](https://golang.org/pkg/net/http/#Hijacker) - */ - hijack(): [net.Conn, (bufio.ReadWriter)] - } - interface Response { - /** - * Unwrap returns the original http.ResponseWriter. - * ResponseController can be used to access the original http.ResponseWriter. - * See [https://go.dev/blog/go1.20] - */ - unwrap(): http.ResponseWriter - } - interface Routes { - /** - * Reverse reverses route to URL string by replacing path parameters with given params values. - */ - reverse(name: string, ...params: { - }[]): string - } - interface Routes { - /** - * FindByMethodPath searched for matching route info by method and path - */ - findByMethodPath(method: string, path: string): RouteInfo - } - interface Routes { - /** - * FilterByMethod searched for matching route info by method - */ - filterByMethod(method: string): Routes - } - interface Routes { - /** - * FilterByPath searched for matching route info by path - */ - filterByPath(path: string): Routes - } - interface Routes { - /** - * FilterByName searched for matching route info by name - */ - filterByName(name: string): Routes + marshalJSON(): string|Array } +} + +/** + * Package context defines the Context type, which carries deadlines, + * cancellation signals, and other request-scoped values across API boundaries + * and between processes. + * + * Incoming requests to a server should create a [Context], and outgoing + * calls to servers should accept a Context. The chain of function + * calls between them must propagate the Context, optionally replacing + * it with a derived Context created using [WithCancel], [WithDeadline], + * [WithTimeout], or [WithValue]. + * + * A Context may be canceled to indicate that work done on its behalf should stop. + * A Context with a deadline is canceled after the deadline passes. + * When a Context is canceled, all Contexts derived from it are also canceled. + * + * The [WithCancel], [WithDeadline], and [WithTimeout] functions take a + * Context (the parent) and return a derived Context (the child) and a + * [CancelFunc]. Calling the CancelFunc directly cancels the child and its + * children, removes the parent's reference to the child, and stops + * any associated timers. Failing to call the CancelFunc leaks the + * child and its children until the parent is canceled. The go vet tool + * checks that CancelFuncs are used on all control-flow paths. + * + * The [WithCancelCause], [WithDeadlineCause], and [WithTimeoutCause] functions + * return a [CancelCauseFunc], which takes an error and records it as + * the cancellation cause. Calling [Cause] on the canceled context + * or any of its children retrieves the cause. If no cause is specified, + * Cause(ctx) returns the same value as ctx.Err(). + * + * Programs that use Contexts should follow these rules to keep interfaces + * consistent across packages and enable static analysis tools to check context + * propagation: + * + * Do not store Contexts inside a struct type; instead, pass a Context + * explicitly to each function that needs it. This is discussed further in + * https://go.dev/blog/context-and-structs. The Context should be the first + * parameter, typically named ctx: + * + * ``` + * func DoSomething(ctx context.Context, arg Arg) error { + * // ... use ctx ... + * } + * ``` + * + * Do not pass a nil [Context], even if a function permits it. Pass [context.TODO] + * if you are unsure about which Context to use. + * + * Use context Values only for request-scoped data that transits processes and + * APIs, not for passing optional parameters to functions. + * + * The same Context may be passed to functions running in different goroutines; + * Contexts are safe for simultaneous use by multiple goroutines. + * + * See https://go.dev/blog/context for example code for a server that uses + * Contexts. + */ +namespace context { /** - * Router is interface for routing request contexts to registered routes. + * A Context carries a deadline, a cancellation signal, and other values across + * API boundaries. * - * Contract between Echo/Context instance and the router: - * ``` - * - all routes must be added through methods on echo.Echo instance. - * Reason: Echo instance uses RouteInfo.Params() length to allocate slice for paths parameters (see `Echo.contextPathParamAllocSize`). - * - Router must populate Context during Router.Route call with: - * - RoutableContext.SetPath - * - RoutableContext.SetRawPathParams (IMPORTANT! with same slice pointer that c.RawPathParams() returns) - * - RoutableContext.SetRouteInfo - * And optionally can set additional information to Context with RoutableContext.Set - * ``` + * Context's methods may be called by multiple goroutines simultaneously. */ - interface Router { + interface Context { [key:string]: any; /** - * Add registers Routable with the Router and returns registered RouteInfo - */ - add(routable: Routable): RouteInfo - /** - * Remove removes route from the Router - */ - remove(method: string, path: string): void - /** - * Routes returns information about all registered routes - */ - routes(): Routes - /** - * Route searches Router for matching route and applies it to the given context. In case when no matching method - * was not found (405) or no matching route exists for path (404), router will return its implementation of 405/404 - * handler function. + * Deadline returns the time when work done on behalf of this context + * should be canceled. Deadline returns ok==false when no deadline is + * set. Successive calls to Deadline return the same results. */ - route(c: RoutableContext): HandlerFunc - } - /** - * Routable is interface for registering Route with Router. During route registration process the Router will - * convert Routable to RouteInfo with ToRouteInfo method. By creating custom implementation of Routable additional - * information about registered route can be stored in Routes (i.e. privileges used with route etc.) - */ - interface Routable { - [key:string]: any; + deadline(): [time.Time, boolean] /** - * ToRouteInfo converts Routable to RouteInfo + * Done returns a channel that's closed when work done on behalf of this + * context should be canceled. Done may return nil if this context can + * never be canceled. Successive calls to Done return the same value. + * The close of the Done channel may happen asynchronously, + * after the cancel function returns. * - * This method is meant to be used by Router after it parses url for path parameters, to store information about - * route just added. - */ - toRouteInfo(params: Array): RouteInfo - /** - * ToRoute converts Routable to Route which Router uses to register the method handler for path. + * WithCancel arranges for Done to be closed when cancel is called; + * WithDeadline arranges for Done to be closed when the deadline + * expires; WithTimeout arranges for Done to be closed when the timeout + * elapses. * - * This method is meant to be used by Router to get fields (including handler and middleware functions) needed to - * add Route to Router. - */ - toRoute(): Route - /** - * ForGroup recreates routable with added group prefix and group middlewares it is grouped to. + * Done is provided for use in select statements: + * + * // Stream generates values with DoSomething and sends them to out + * // until DoSomething returns an error or ctx.Done is closed. + * func Stream(ctx context.Context, out chan<- Value) error { + * for { + * v, err := DoSomething(ctx) + * if err != nil { + * return err + * } + * select { + * case <-ctx.Done(): + * return ctx.Err() + * case out <- v: + * } + * } + * } * - * Is necessary for Echo.Group to be able to add/register Routable with Router and having group prefix and group - * middlewares included in actually registered Route. + * See https://blog.golang.org/pipelines for more examples of how to use + * a Done channel for cancellation. */ - forGroup(pathPrefix: string, middlewares: Array): Routable - } - /** - * Routes is collection of RouteInfo instances with various helper methods. - */ - interface Routes extends Array{} - /** - * RouteInfo describes registered route base fields. - * Method+Path pair uniquely identifies the Route. Name can have duplicates. - */ - interface RouteInfo { - [key:string]: any; - method(): string - path(): string - name(): string - params(): Array + done(): undefined /** - * Reverse reverses route to URL string by replacing path parameters with given params values. + * If Done is not yet closed, Err returns nil. + * If Done is closed, Err returns a non-nil error explaining why: + * DeadlineExceeded if the context's deadline passed, + * or Canceled if the context was canceled for some other reason. + * After Err returns a non-nil error, successive calls to Err return the same error. */ - reverse(...params: { - }[]): string - } - /** - * PathParams is collections of PathParam instances with various helper methods - */ - interface PathParams extends Array{} - interface PathParams { + err(): void /** - * Get returns path parameter value for given name or default value. + * Value returns the value associated with this context for key, or nil + * if no value is associated with key. Successive calls to Value with + * the same key returns the same result. + * + * Use context values only for request-scoped data that transits + * processes and API boundaries, not for passing optional parameters to + * functions. + * + * A key identifies a specific value in a Context. Functions that wish + * to store values in Context typically allocate a key in a global + * variable then use that key as the argument to context.WithValue and + * Context.Value. A key can be any type that supports equality; + * packages should define keys as an unexported type to avoid + * collisions. + * + * Packages that define a Context key should provide type-safe accessors + * for the values stored using that key: + * + * ``` + * // Package user defines a User type that's stored in Contexts. + * package user + * + * import "context" + * + * // User is the type of value stored in the Contexts. + * type User struct {...} + * + * // key is an unexported type for keys defined in this package. + * // This prevents collisions with keys defined in other packages. + * type key int + * + * // userKey is the key for user.User values in Contexts. It is + * // unexported; clients use user.NewContext and user.FromContext + * // instead of using this key directly. + * var userKey key + * + * // NewContext returns a new Context that carries value u. + * func NewContext(ctx context.Context, u *User) context.Context { + * return context.WithValue(ctx, userKey, u) + * } + * + * // FromContext returns the User value stored in ctx, if any. + * func FromContext(ctx context.Context) (*User, bool) { + * u, ok := ctx.Value(userKey).(*User) + * return u, ok + * } + * ``` */ - get(name: string, defaultValue: string): string + value(key: any): any } } @@ -16695,80 +16228,147 @@ namespace echo { */ namespace sql { /** - * IsolationLevel is the transaction isolation level used in [TxOptions]. + * TxOptions holds the transaction options to be used in [DB.BeginTx]. */ - interface IsolationLevel extends Number{} - interface IsolationLevel { + interface TxOptions { /** - * String returns the name of the transaction isolation level. + * Isolation is the transaction isolation level. + * If zero, the driver or database's default level is used. */ - string(): string + isolation: IsolationLevel + readOnly: boolean } /** - * DBStats contains database statistics. + * NullString represents a string that may be null. + * NullString implements the [Scanner] interface so + * it can be used as a scan destination: + * + * ``` + * var s NullString + * err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s) + * ... + * if s.Valid { + * // use s.String + * } else { + * // NULL value + * } + * ``` */ - interface DBStats { - maxOpenConnections: number // Maximum number of open connections to the database. + interface NullString { + string: string + valid: boolean // Valid is true if String is not NULL + } + interface NullString { /** - * Pool Status + * Scan implements the [Scanner] interface. */ - openConnections: number // The number of established connections both in use and idle. - inUse: number // The number of connections currently in use. - idle: number // The number of idle connections. + scan(value: any): void + } + interface NullString { /** - * Counters + * Value implements the [driver.Valuer] interface. */ - waitCount: number // The total number of connections waited for. - waitDuration: time.Duration // The total time blocked waiting for a new connection. - maxIdleClosed: number // The total number of connections closed due to SetMaxIdleConns. - maxIdleTimeClosed: number // The total number of connections closed due to SetConnMaxIdleTime. - maxLifetimeClosed: number // The total number of connections closed due to SetConnMaxLifetime. + value(): any } /** - * Conn represents a single database connection rather than a pool of database - * connections. Prefer running queries from [DB] unless there is a specific - * need for a continuous single database connection. - * - * A Conn must call [Conn.Close] to return the connection to the database pool - * and may do so concurrently with a running query. + * DB is a database handle representing a pool of zero or more + * underlying connections. It's safe for concurrent use by multiple + * goroutines. * - * After a call to [Conn.Close], all operations on the - * connection fail with [ErrConnDone]. + * The sql package creates and frees connections automatically; it + * also maintains a free pool of idle connections. If the database has + * a concept of per-connection state, such state can be reliably observed + * within a transaction ([Tx]) or connection ([Conn]). Once [DB.Begin] is called, the + * returned [Tx] is bound to a single connection. Once [Tx.Commit] or + * [Tx.Rollback] is called on the transaction, that transaction's + * connection is returned to [DB]'s idle connection pool. The pool size + * can be controlled with [DB.SetMaxIdleConns]. */ - interface Conn { + interface DB { } - interface Conn { + interface DB { /** - * PingContext verifies the connection to the database is still alive. + * PingContext verifies a connection to the database is still alive, + * establishing a connection if necessary. */ pingContext(ctx: context.Context): void } - interface Conn { + interface DB { /** - * ExecContext executes a query without returning any rows. - * The args are for any placeholder parameters in the query. + * Ping verifies a connection to the database is still alive, + * establishing a connection if necessary. + * + * Ping uses [context.Background] internally; to specify the context, use + * [DB.PingContext]. */ - execContext(ctx: context.Context, query: string, ...args: any[]): Result + ping(): void } - interface Conn { + interface DB { /** - * QueryContext executes a query that returns rows, typically a SELECT. - * The args are for any placeholder parameters in the query. - */ - queryContext(ctx: context.Context, query: string, ...args: any[]): (Rows) + * Close closes the database and prevents new queries from starting. + * Close then waits for all queries that have started processing on the server + * to finish. + * + * It is rare to Close a [DB], as the [DB] handle is meant to be + * long-lived and shared between many goroutines. + */ + close(): void } - interface Conn { + interface DB { /** - * QueryRowContext executes a query that is expected to return at most one row. - * QueryRowContext always returns a non-nil value. Errors are deferred until - * the [*Row.Scan] method is called. - * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. - * Otherwise, the [*Row.Scan] scans the first selected row and discards - * the rest. + * SetMaxIdleConns sets the maximum number of connections in the idle + * connection pool. + * + * If MaxOpenConns is greater than 0 but less than the new MaxIdleConns, + * then the new MaxIdleConns will be reduced to match the MaxOpenConns limit. + * + * If n <= 0, no idle connections are retained. + * + * The default max idle connections is currently 2. This may change in + * a future release. */ - queryRowContext(ctx: context.Context, query: string, ...args: any[]): (Row) + setMaxIdleConns(n: number): void } - interface Conn { + interface DB { + /** + * SetMaxOpenConns sets the maximum number of open connections to the database. + * + * If MaxIdleConns is greater than 0 and the new MaxOpenConns is less than + * MaxIdleConns, then MaxIdleConns will be reduced to match the new + * MaxOpenConns limit. + * + * If n <= 0, then there is no limit on the number of open connections. + * The default is 0 (unlimited). + */ + setMaxOpenConns(n: number): void + } + interface DB { + /** + * SetConnMaxLifetime sets the maximum amount of time a connection may be reused. + * + * Expired connections may be closed lazily before reuse. + * + * If d <= 0, connections are not closed due to a connection's age. + */ + setConnMaxLifetime(d: time.Duration): void + } + interface DB { + /** + * SetConnMaxIdleTime sets the maximum amount of time a connection may be idle. + * + * Expired connections may be closed lazily before reuse. + * + * If d <= 0, connections are not closed due to a connection's idle time. + */ + setConnMaxIdleTime(d: time.Duration): void + } + interface DB { + /** + * Stats returns database statistics. + */ + stats(): DBStats + } + interface DB { /** * PrepareContext creates a prepared statement for later queries or executions. * Multiple queries or executions may be run concurrently from the @@ -16781,3919 +16381,7446 @@ namespace sql { */ prepareContext(ctx: context.Context, query: string): (Stmt) } - interface Conn { + interface DB { /** - * Raw executes f exposing the underlying driver connection for the - * duration of f. The driverConn must not be used outside of f. + * Prepare creates a prepared statement for later queries or executions. + * Multiple queries or executions may be run concurrently from the + * returned statement. + * The caller must call the statement's [*Stmt.Close] method + * when the statement is no longer needed. * - * Once f returns and err is not [driver.ErrBadConn], the [Conn] will continue to be usable - * until [Conn.Close] is called. + * Prepare uses [context.Background] internally; to specify the context, use + * [DB.PrepareContext]. */ - raw(f: (driverConn: any) => void): void + prepare(query: string): (Stmt) } - interface Conn { + interface DB { /** - * BeginTx starts a transaction. - * - * The provided context is used until the transaction is committed or rolled back. - * If the context is canceled, the sql package will roll back - * the transaction. [Tx.Commit] will return an error if the context provided to - * BeginTx is canceled. + * ExecContext executes a query without returning any rows. + * The args are for any placeholder parameters in the query. + */ + execContext(ctx: context.Context, query: string, ...args: any[]): Result + } + interface DB { + /** + * Exec executes a query without returning any rows. + * The args are for any placeholder parameters in the query. * - * The provided [TxOptions] is optional and may be nil if defaults should be used. - * If a non-default isolation level is used that the driver doesn't support, - * an error will be returned. + * Exec uses [context.Background] internally; to specify the context, use + * [DB.ExecContext]. */ - beginTx(ctx: context.Context, opts: TxOptions): (Tx) + exec(query: string, ...args: any[]): Result } - interface Conn { + interface DB { /** - * Close returns the connection to the connection pool. - * All operations after a Close will return with [ErrConnDone]. - * Close is safe to call concurrently with other operations and will - * block until all other operations finish. It may be useful to first - * cancel any used context and then call close directly after. + * QueryContext executes a query that returns rows, typically a SELECT. + * The args are for any placeholder parameters in the query. */ - close(): void + queryContext(ctx: context.Context, query: string, ...args: any[]): (Rows) } - /** - * ColumnType contains the name and type of a column. - */ - interface ColumnType { + interface DB { + /** + * Query executes a query that returns rows, typically a SELECT. + * The args are for any placeholder parameters in the query. + * + * Query uses [context.Background] internally; to specify the context, use + * [DB.QueryContext]. + */ + query(query: string, ...args: any[]): (Rows) } - interface ColumnType { + interface DB { /** - * Name returns the name or alias of the column. + * QueryRowContext executes a query that is expected to return at most one row. + * QueryRowContext always returns a non-nil value. Errors are deferred until + * [Row]'s Scan method is called. + * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. + * Otherwise, [*Row.Scan] scans the first selected row and discards + * the rest. */ - name(): string + queryRowContext(ctx: context.Context, query: string, ...args: any[]): (Row) } - interface ColumnType { + interface DB { /** - * Length returns the column type length for variable length column types such - * as text and binary field types. If the type length is unbounded the value will - * be [math.MaxInt64] (any database limits will still apply). - * If the column type is not variable length, such as an int, or if not supported - * by the driver ok is false. + * QueryRow executes a query that is expected to return at most one row. + * QueryRow always returns a non-nil value. Errors are deferred until + * [Row]'s Scan method is called. + * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. + * Otherwise, [*Row.Scan] scans the first selected row and discards + * the rest. + * + * QueryRow uses [context.Background] internally; to specify the context, use + * [DB.QueryRowContext]. */ - length(): [number, boolean] + queryRow(query: string, ...args: any[]): (Row) } - interface ColumnType { + interface DB { /** - * DecimalSize returns the scale and precision of a decimal type. - * If not applicable or if not supported ok is false. + * BeginTx starts a transaction. + * + * The provided context is used until the transaction is committed or rolled back. + * If the context is canceled, the sql package will roll back + * the transaction. [Tx.Commit] will return an error if the context provided to + * BeginTx is canceled. + * + * The provided [TxOptions] is optional and may be nil if defaults should be used. + * If a non-default isolation level is used that the driver doesn't support, + * an error will be returned. */ - decimalSize(): [number, number, boolean] + beginTx(ctx: context.Context, opts: TxOptions): (Tx) } - interface ColumnType { + interface DB { /** - * ScanType returns a Go type suitable for scanning into using [Rows.Scan]. - * If a driver does not support this property ScanType will return - * the type of an empty interface. + * Begin starts a transaction. The default isolation level is dependent on + * the driver. + * + * Begin uses [context.Background] internally; to specify the context, use + * [DB.BeginTx]. */ - scanType(): any + begin(): (Tx) } - interface ColumnType { + interface DB { /** - * Nullable reports whether the column may be null. - * If a driver does not support this property ok will be false. + * Driver returns the database's underlying driver. */ - nullable(): [boolean, boolean] + driver(): any } - interface ColumnType { + interface DB { /** - * DatabaseTypeName returns the database system name of the column type. If an empty - * string is returned, then the driver type name is not supported. - * Consult your driver documentation for a list of driver data types. [ColumnType.Length] specifiers - * are not included. - * Common type names include "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL", - * "INT", and "BIGINT". + * Conn returns a single connection by either opening a new connection + * or returning an existing connection from the connection pool. Conn will + * block until either a connection is returned or ctx is canceled. + * Queries run on the same Conn will be run in the same database session. + * + * Every Conn must be returned to the database pool after use by + * calling [Conn.Close]. */ - databaseTypeName(): string + conn(ctx: context.Context): (Conn) } /** - * Row is the result of calling [DB.QueryRow] to select a single row. + * Tx is an in-progress database transaction. + * + * A transaction must end with a call to [Tx.Commit] or [Tx.Rollback]. + * + * After a call to [Tx.Commit] or [Tx.Rollback], all operations on the + * transaction fail with [ErrTxDone]. + * + * The statements prepared for a transaction by calling + * the transaction's [Tx.Prepare] or [Tx.Stmt] methods are closed + * by the call to [Tx.Commit] or [Tx.Rollback]. */ - interface Row { + interface Tx { } - interface Row { + interface Tx { /** - * Scan copies the columns from the matched row into the values - * pointed at by dest. See the documentation on [Rows.Scan] for details. - * If more than one row matches the query, - * Scan uses the first row and discards the rest. If no row matches - * the query, Scan returns [ErrNoRows]. + * Commit commits the transaction. */ - scan(...dest: any[]): void + commit(): void } - interface Row { + interface Tx { /** - * Err provides a way for wrapping packages to check for - * query errors without calling [Row.Scan]. - * Err returns the error, if any, that was encountered while running the query. - * If this error is not nil, this error will also be returned from [Row.Scan]. + * Rollback aborts the transaction. */ - err(): void - } -} - -namespace settings { - // @ts-ignore - import validation = ozzo_validation - interface TokenConfig { - secret: string - duration: number + rollback(): void } - interface TokenConfig { + interface Tx { /** - * Validate makes TokenConfig validatable by implementing [validation.Validatable] interface. - */ - validate(): void - } - interface SmtpConfig { - enabled: boolean - host: string - port: number - username: string - password: string - /** - * SMTP AUTH - PLAIN (default) or LOGIN - */ - authMethod: string - /** - * Whether to enforce TLS encryption for the mail server connection. + * PrepareContext creates a prepared statement for use within a transaction. * - * When set to false StartTLS command is send, leaving the server - * to decide whether to upgrade the connection or not. - */ - tls: boolean - /** - * LocalName is optional domain name or IP address used for the - * EHLO/HELO exchange (if not explicitly set, defaults to "localhost"). + * The returned statement operates within the transaction and will be closed + * when the transaction has been committed or rolled back. * - * This is required only by some SMTP servers, such as Gmail SMTP-relay. + * To use an existing prepared statement on this transaction, see [Tx.Stmt]. + * + * The provided context will be used for the preparation of the context, not + * for the execution of the returned statement. The returned statement + * will run in the transaction context. */ - localName: string + prepareContext(ctx: context.Context, query: string): (Stmt) } - interface SmtpConfig { + interface Tx { /** - * Validate makes SmtpConfig validatable by implementing [validation.Validatable] interface. + * Prepare creates a prepared statement for use within a transaction. + * + * The returned statement operates within the transaction and will be closed + * when the transaction has been committed or rolled back. + * + * To use an existing prepared statement on this transaction, see [Tx.Stmt]. + * + * Prepare uses [context.Background] internally; to specify the context, use + * [Tx.PrepareContext]. */ - validate(): void - } - interface S3Config { - enabled: boolean - bucket: string - region: string - endpoint: string - accessKey: string - secret: string - forcePathStyle: boolean + prepare(query: string): (Stmt) } - interface S3Config { + interface Tx { /** - * Validate makes S3Config validatable by implementing [validation.Validatable] interface. + * StmtContext returns a transaction-specific prepared statement from + * an existing statement. + * + * Example: + * + * ``` + * updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?") + * ... + * tx, err := db.Begin() + * ... + * res, err := tx.StmtContext(ctx, updateMoney).Exec(123.45, 98293203) + * ``` + * + * The provided context is used for the preparation of the statement, not for the + * execution of the statement. + * + * The returned statement operates within the transaction and will be closed + * when the transaction has been committed or rolled back. */ - validate(): void + stmtContext(ctx: context.Context, stmt: Stmt): (Stmt) } - interface BackupsConfig { + interface Tx { /** - * Cron is a cron expression to schedule auto backups, eg. "* * * * *". + * Stmt returns a transaction-specific prepared statement from + * an existing statement. * - * Leave it empty to disable the auto backups functionality. - */ - cron: string - /** - * CronMaxKeep is the max number of cron generated backups to - * keep before removing older entries. + * Example: * - * This field works only when the cron config has valid cron expression. - */ - cronMaxKeep: number - /** - * S3 is an optional S3 storage config specifying where to store the app backups. + * ``` + * updateMoney, err := db.Prepare("UPDATE balance SET money=money+? WHERE id=?") + * ... + * tx, err := db.Begin() + * ... + * res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203) + * ``` + * + * The returned statement operates within the transaction and will be closed + * when the transaction has been committed or rolled back. + * + * Stmt uses [context.Background] internally; to specify the context, use + * [Tx.StmtContext]. */ - s3: S3Config + stmt(stmt: Stmt): (Stmt) } - interface BackupsConfig { + interface Tx { /** - * Validate makes BackupsConfig validatable by implementing [validation.Validatable] interface. + * ExecContext executes a query that doesn't return rows. + * For example: an INSERT and UPDATE. */ - validate(): void - } - interface MetaConfig { - appName: string - appUrl: string - hideControls: boolean - senderName: string - senderAddress: string - verificationTemplate: EmailTemplate - resetPasswordTemplate: EmailTemplate - confirmEmailChangeTemplate: EmailTemplate + execContext(ctx: context.Context, query: string, ...args: any[]): Result } - interface MetaConfig { + interface Tx { /** - * Validate makes MetaConfig validatable by implementing [validation.Validatable] interface. + * Exec executes a query that doesn't return rows. + * For example: an INSERT and UPDATE. + * + * Exec uses [context.Background] internally; to specify the context, use + * [Tx.ExecContext]. */ - validate(): void - } - interface LogsConfig { - maxDays: number - minLevel: number - logIp: boolean + exec(query: string, ...args: any[]): Result } - interface LogsConfig { + interface Tx { /** - * Validate makes LogsConfig validatable by implementing [validation.Validatable] interface. + * QueryContext executes a query that returns rows, typically a SELECT. */ - validate(): void - } - interface AuthProviderConfig { - enabled: boolean - clientId: string - clientSecret: string - authUrl: string - tokenUrl: string - userApiUrl: string - displayName: string - pkce?: boolean + queryContext(ctx: context.Context, query: string, ...args: any[]): (Rows) } - interface AuthProviderConfig { + interface Tx { /** - * Validate makes `ProviderConfig` validatable by implementing [validation.Validatable] interface. + * Query executes a query that returns rows, typically a SELECT. + * + * Query uses [context.Background] internally; to specify the context, use + * [Tx.QueryContext]. */ - validate(): void + query(query: string, ...args: any[]): (Rows) } - interface AuthProviderConfig { + interface Tx { /** - * SetupProvider loads the current AuthProviderConfig into the specified provider. + * QueryRowContext executes a query that is expected to return at most one row. + * QueryRowContext always returns a non-nil value. Errors are deferred until + * [Row]'s Scan method is called. + * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. + * Otherwise, the [*Row.Scan] scans the first selected row and discards + * the rest. */ - setupProvider(provider: auth.Provider): void - } - /** - * Deprecated: Will be removed in v0.9+ - */ - interface EmailAuthConfig { - enabled: boolean - exceptDomains: Array - onlyDomains: Array - minPasswordLength: number + queryRowContext(ctx: context.Context, query: string, ...args: any[]): (Row) } - interface EmailAuthConfig { + interface Tx { /** - * Deprecated: Will be removed in v0.9+ + * QueryRow executes a query that is expected to return at most one row. + * QueryRow always returns a non-nil value. Errors are deferred until + * [Row]'s Scan method is called. + * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. + * Otherwise, the [*Row.Scan] scans the first selected row and discards + * the rest. + * + * QueryRow uses [context.Background] internally; to specify the context, use + * [Tx.QueryRowContext]. */ - validate(): void + queryRow(query: string, ...args: any[]): (Row) } -} - -/** - * Package schema implements custom Schema and SchemaField datatypes - * for handling the Collection schema definitions. - */ -namespace schema { - // @ts-ignore - import validation = ozzo_validation /** - * SchemaField defines a single schema field structure. + * Stmt is a prepared statement. + * A Stmt is safe for concurrent use by multiple goroutines. + * + * If a Stmt is prepared on a [Tx] or [Conn], it will be bound to a single + * underlying connection forever. If the [Tx] or [Conn] closes, the Stmt will + * become unusable and all operations will return an error. + * If a Stmt is prepared on a [DB], it will remain usable for the lifetime of the + * [DB]. When the Stmt needs to execute on a new underlying connection, it will + * prepare itself on the new connection automatically. */ - interface SchemaField { - system: boolean - id: string - name: string - type: string - required: boolean - /** - * Presentable indicates whether the field is suitable for - * visualization purposes (eg. in the Admin UI relation views). - */ - presentable: boolean - /** - * Deprecated: This field is no-op and will be removed in future versions. - * Please use the collection.Indexes field to define a unique constraint. - */ - unique: boolean - options: any - } - interface SchemaField { - /** - * ColDefinition returns the field db column type definition as string. - */ - colDefinition(): string - } - interface SchemaField { - /** - * String serializes and returns the current field as string. - */ - string(): string + interface Stmt { } - interface SchemaField { + interface Stmt { /** - * MarshalJSON implements the [json.Marshaler] interface. + * ExecContext executes a prepared statement with the given arguments and + * returns a [Result] summarizing the effect of the statement. */ - marshalJSON(): string|Array + execContext(ctx: context.Context, ...args: any[]): Result } - interface SchemaField { + interface Stmt { /** - * UnmarshalJSON implements the [json.Unmarshaler] interface. + * Exec executes a prepared statement with the given arguments and + * returns a [Result] summarizing the effect of the statement. * - * The schema field options are auto initialized on success. + * Exec uses [context.Background] internally; to specify the context, use + * [Stmt.ExecContext]. */ - unmarshalJSON(data: string|Array): void + exec(...args: any[]): Result } - interface SchemaField { + interface Stmt { /** - * Validate makes `SchemaField` validatable by implementing [validation.Validatable] interface. + * QueryContext executes a prepared query statement with the given arguments + * and returns the query results as a [*Rows]. */ - validate(): void + queryContext(ctx: context.Context, ...args: any[]): (Rows) } - interface SchemaField { + interface Stmt { /** - * InitOptions initializes the current field options based on its type. + * Query executes a prepared query statement with the given arguments + * and returns the query results as a *Rows. * - * Returns error on unknown field type. + * Query uses [context.Background] internally; to specify the context, use + * [Stmt.QueryContext]. */ - initOptions(): void + query(...args: any[]): (Rows) } - interface SchemaField { + interface Stmt { /** - * PrepareValue returns normalized and properly formatted field value. + * QueryRowContext executes a prepared query statement with the given arguments. + * If an error occurs during the execution of the statement, that error will + * be returned by a call to Scan on the returned [*Row], which is always non-nil. + * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. + * Otherwise, the [*Row.Scan] scans the first selected row and discards + * the rest. */ - prepareValue(value: any): any + queryRowContext(ctx: context.Context, ...args: any[]): (Row) } - interface SchemaField { + interface Stmt { /** - * PrepareValueWithModifier returns normalized and properly formatted field value - * by "merging" baseValue with the modifierValue based on the specified modifier (+ or -). - */ - prepareValueWithModifier(baseValue: any, modifier: string, modifierValue: any): any - } -} - -/** - * Package models implements all PocketBase DB models and DTOs. - */ -namespace models { - /** - * Model defines an interface with common methods that all db models should have. - */ - interface Model { - [key:string]: any; - tableName(): string - isNew(): boolean - markAsNew(): void - markAsNotNew(): void - hasId(): boolean - getId(): string - setId(id: string): void - getCreated(): types.DateTime - getUpdated(): types.DateTime - refreshId(): void - refreshCreated(): void - refreshUpdated(): void - } - /** - * BaseModel defines common fields and methods used by all other models. - */ - interface BaseModel { - id: string - created: types.DateTime - updated: types.DateTime - } - interface BaseModel { - /** - * HasId returns whether the model has a nonzero id. + * QueryRow executes a prepared query statement with the given arguments. + * If an error occurs during the execution of the statement, that error will + * be returned by a call to Scan on the returned [*Row], which is always non-nil. + * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. + * Otherwise, the [*Row.Scan] scans the first selected row and discards + * the rest. + * + * Example usage: + * + * ``` + * var name string + * err := nameByUseridStmt.QueryRow(id).Scan(&name) + * ``` + * + * QueryRow uses [context.Background] internally; to specify the context, use + * [Stmt.QueryRowContext]. */ - hasId(): boolean + queryRow(...args: any[]): (Row) } - interface BaseModel { + interface Stmt { /** - * GetId returns the model id. + * Close closes the statement. */ - getId(): string + close(): void } - interface BaseModel { - /** - * SetId sets the model id to the provided string value. - */ - setId(id: string): void + /** + * Rows is the result of a query. Its cursor starts before the first row + * of the result set. Use [Rows.Next] to advance from row to row. + */ + interface Rows { } - interface BaseModel { + interface Rows { /** - * MarkAsNew marks the model as "new" (aka. enforces m.IsNew() to be true). + * Next prepares the next result row for reading with the [Rows.Scan] method. It + * returns true on success, or false if there is no next result row or an error + * happened while preparing it. [Rows.Err] should be consulted to distinguish between + * the two cases. + * + * Every call to [Rows.Scan], even the first one, must be preceded by a call to [Rows.Next]. */ - markAsNew(): void + next(): boolean } - interface BaseModel { + interface Rows { /** - * MarkAsNotNew marks the model as "not new" (aka. enforces m.IsNew() to be false) + * NextResultSet prepares the next result set for reading. It reports whether + * there is further result sets, or false if there is no further result set + * or if there is an error advancing to it. The [Rows.Err] method should be consulted + * to distinguish between the two cases. + * + * After calling NextResultSet, the [Rows.Next] method should always be called before + * scanning. If there are further result sets they may not have rows in the result + * set. */ - markAsNotNew(): void + nextResultSet(): boolean } - interface BaseModel { + interface Rows { /** - * IsNew indicates what type of db query (insert or update) - * should be used with the model instance. + * Err returns the error, if any, that was encountered during iteration. + * Err may be called after an explicit or implicit [Rows.Close]. */ - isNew(): boolean + err(): void } - interface BaseModel { + interface Rows { /** - * GetCreated returns the model Created datetime. + * Columns returns the column names. + * Columns returns an error if the rows are closed. */ - getCreated(): types.DateTime + columns(): Array } - interface BaseModel { + interface Rows { /** - * GetUpdated returns the model Updated datetime. + * ColumnTypes returns column information such as column type, length, + * and nullable. Some information may not be available from some drivers. */ - getUpdated(): types.DateTime + columnTypes(): Array<(ColumnType | undefined)> } - interface BaseModel { + interface Rows { /** - * RefreshId generates and sets a new model id. + * Scan copies the columns in the current row into the values pointed + * at by dest. The number of values in dest must be the same as the + * number of columns in [Rows]. * - * The generated id is a cryptographically random 15 characters length string. - */ - refreshId(): void - } - interface BaseModel { - /** - * RefreshCreated updates the model Created field with the current datetime. - */ - refreshCreated(): void - } - interface BaseModel { - /** - * RefreshUpdated updates the model Updated field with the current datetime. - */ - refreshUpdated(): void - } - interface BaseModel { - /** - * PostScan implements the [dbx.PostScanner] interface. + * Scan converts columns read from the database into the following + * common Go types and special types provided by the sql package: * - * It is executed right after the model was populated with the db row values. - */ - postScan(): void - } - // @ts-ignore - import validation = ozzo_validation - /** - * CollectionBaseOptions defines the "base" Collection.Options fields. - */ - interface CollectionBaseOptions { - } - interface CollectionBaseOptions { - /** - * Validate implements [validation.Validatable] interface. + * ``` + * *string + * *[]byte + * *int, *int8, *int16, *int32, *int64 + * *uint, *uint8, *uint16, *uint32, *uint64 + * *bool + * *float32, *float64 + * *interface{} + * *RawBytes + * *Rows (cursor value) + * any type implementing Scanner (see Scanner docs) + * ``` + * + * In the most simple case, if the type of the value from the source + * column is an integer, bool or string type T and dest is of type *T, + * Scan simply assigns the value through the pointer. + * + * Scan also converts between string and numeric types, as long as no + * information would be lost. While Scan stringifies all numbers + * scanned from numeric database columns into *string, scans into + * numeric types are checked for overflow. For example, a float64 with + * value 300 or a string with value "300" can scan into a uint16, but + * not into a uint8, though float64(255) or "255" can scan into a + * uint8. One exception is that scans of some float64 numbers to + * strings may lose information when stringifying. In general, scan + * floating point columns into *float64. + * + * If a dest argument has type *[]byte, Scan saves in that argument a + * copy of the corresponding data. The copy is owned by the caller and + * can be modified and held indefinitely. The copy can be avoided by + * using an argument of type [*RawBytes] instead; see the documentation + * for [RawBytes] for restrictions on its use. + * + * If an argument has type *interface{}, Scan copies the value + * provided by the underlying driver without conversion. When scanning + * from a source value of type []byte to *interface{}, a copy of the + * slice is made and the caller owns the result. + * + * Source values of type [time.Time] may be scanned into values of type + * *time.Time, *interface{}, *string, or *[]byte. When converting to + * the latter two, [time.RFC3339Nano] is used. + * + * Source values of type bool may be scanned into types *bool, + * *interface{}, *string, *[]byte, or [*RawBytes]. + * + * For scanning into *bool, the source may be true, false, 1, 0, or + * string inputs parseable by [strconv.ParseBool]. + * + * Scan can also convert a cursor returned from a query, such as + * "select cursor(select * from my_table) from dual", into a + * [*Rows] value that can itself be scanned from. The parent + * select query will close any cursor [*Rows] if the parent [*Rows] is closed. + * + * If any of the first arguments implementing [Scanner] returns an error, + * that error will be wrapped in the returned error. */ - validate(): void - } - /** - * CollectionAuthOptions defines the "auth" Collection.Options fields. - */ - interface CollectionAuthOptions { - manageRule?: string - allowOAuth2Auth: boolean - allowUsernameAuth: boolean - allowEmailAuth: boolean - requireEmail: boolean - exceptEmailDomains: Array - onlyVerified: boolean - onlyEmailDomains: Array - minPasswordLength: number + scan(...dest: any[]): void } - interface CollectionAuthOptions { + interface Rows { /** - * Validate implements [validation.Validatable] interface. + * Close closes the [Rows], preventing further enumeration. If [Rows.Next] is called + * and returns false and there are no further result sets, + * the [Rows] are closed automatically and it will suffice to check the + * result of [Rows.Err]. Close is idempotent and does not affect the result of [Rows.Err]. */ - validate(): void + close(): void } /** - * CollectionViewOptions defines the "view" Collection.Options fields. + * A Result summarizes an executed SQL command. */ - interface CollectionViewOptions { - query: string - } - interface CollectionViewOptions { + interface Result { + [key:string]: any; /** - * Validate implements [validation.Validatable] interface. + * LastInsertId returns the integer generated by the database + * in response to a command. Typically this will be from an + * "auto increment" column when inserting a new row. Not all + * databases support this feature, and the syntax of such + * statements varies. */ - validate(): void - } - type _subwARCM = BaseModel - interface Log extends _subwARCM { - data: types.JsonMap - message: string - level: number - } - interface Log { - tableName(): string - } - type _subqJNdp = BaseModel - interface Param extends _subqJNdp { - key: string - value: types.JsonRaw - } - interface Param { - tableName(): string - } - interface TableInfoRow { + lastInsertId(): number /** - * the `db:"pk"` tag has special semantic so we cannot rename - * the original field without specifying a custom mapper + * RowsAffected returns the number of rows affected by an + * update, insert, or delete. Not every database or database + * driver may support this. */ - pk: number - index: number - name: string - type: string - notNull: boolean - defaultValue: types.JsonRaw + rowsAffected(): number } } /** - * Package daos handles common PocketBase DB model manipulations. + * Package syntax parses regular expressions into parse trees and compiles + * parse trees into programs. Most clients of regular expressions will use the + * facilities of package [regexp] (such as [regexp.Compile] and [regexp.Match]) instead of this package. * - * Think of daos as DB repository and service layer in one. - */ -namespace daos { - interface LogsStatsItem { - total: number - date: types.DateTime - } - /** - * ExpandFetchFunc defines the function that is used to fetch the expanded relation records. - */ - interface ExpandFetchFunc {(relCollection: models.Collection, relIds: Array): Array<(models.Record | undefined)> } - // @ts-ignore - import validation = ozzo_validation -} - -namespace hook { - /** - * Hook defines a concurrent safe structure for handling event hooks - * (aka. callbacks propagation). - */ - interface Hook { - } - interface Hook { - /** - * PreAdd registers a new handler to the hook by prepending it to the existing queue. - * - * Returns an autogenerated hook id that could be used later to remove the hook with Hook.Remove(id). - */ - preAdd(fn: Handler): string - } - interface Hook { - /** - * Add registers a new handler to the hook by appending it to the existing queue. - * - * Returns an autogenerated hook id that could be used later to remove the hook with Hook.Remove(id). - */ - add(fn: Handler): string - } - interface Hook { - /** - * Remove removes a single hook handler by its id. - */ - remove(id: string): void - } - interface Hook { - /** - * RemoveAll removes all registered handlers. - */ - removeAll(): void - } - interface Hook { - /** - * Trigger executes all registered hook handlers one by one - * with the specified `data` as an argument. - * - * Optionally, this method allows also to register additional one off - * handlers that will be temporary appended to the handlers queue. - * - * The execution stops when: - * - hook.StopPropagation is returned in one of the handlers - * - any non-nil error is returned in one of the handlers - */ - trigger(data: T, ...oneOffHandlers: Handler[]): void - } - /** - * TaggedHook defines a proxy hook which register handlers that are triggered only - * if the TaggedHook.tags are empty or includes at least one of the event data tag(s). - */ - type _subTxVwj = mainHook - interface TaggedHook extends _subTxVwj { - } - interface TaggedHook { - /** - * CanTriggerOn checks if the current TaggedHook can be triggered with - * the provided event data tags. - */ - canTriggerOn(tags: Array): boolean - } - interface TaggedHook { - /** - * PreAdd registers a new handler to the hook by prepending it to the existing queue. - * - * The fn handler will be called only if the event data tags satisfy h.CanTriggerOn. - */ - preAdd(fn: Handler): string - } - interface TaggedHook { - /** - * Add registers a new handler to the hook by appending it to the existing queue. - * - * The fn handler will be called only if the event data tags satisfy h.CanTriggerOn. - */ - add(fn: Handler): string - } -} - -/** - * Package slog provides structured logging, - * in which log records include a message, - * a severity level, and various other attributes - * expressed as key-value pairs. - * - * It defines a type, [Logger], - * which provides several methods (such as [Logger.Info] and [Logger.Error]) - * for reporting events of interest. + * # Syntax * - * Each Logger is associated with a [Handler]. - * A Logger output method creates a [Record] from the method arguments - * and passes it to the Handler, which decides how to handle it. - * There is a default Logger accessible through top-level functions - * (such as [Info] and [Error]) that call the corresponding Logger methods. + * The regular expression syntax understood by this package when parsing with the [Perl] flag is as follows. + * Parts of the syntax can be disabled by passing alternate flags to [Parse]. * - * A log record consists of a time, a level, a message, and a set of key-value - * pairs, where the keys are strings and the values may be of any type. - * As an example, + * Single characters: * * ``` - * slog.Info("hello", "count", 3) + * . any character, possibly including newline (flag s=true) + * [xyz] character class + * [^xyz] negated character class + * \d Perl character class + * \D negated Perl character class + * [[:alpha:]] ASCII character class + * [[:^alpha:]] negated ASCII character class + * \pN Unicode character class (one-letter name) + * \p{Greek} Unicode character class + * \PN negated Unicode character class (one-letter name) + * \P{Greek} negated Unicode character class * ``` * - * creates a record containing the time of the call, - * a level of Info, the message "hello", and a single - * pair with key "count" and value 3. - * - * The [Info] top-level function calls the [Logger.Info] method on the default Logger. - * In addition to [Logger.Info], there are methods for Debug, Warn and Error levels. - * Besides these convenience methods for common levels, - * there is also a [Logger.Log] method which takes the level as an argument. - * Each of these methods has a corresponding top-level function that uses the - * default logger. - * - * The default handler formats the log record's message, time, level, and attributes - * as a string and passes it to the [log] package. + * Composites: * * ``` - * 2022/11/08 15:28:26 INFO hello count=3 + * xy x followed by y + * x|y x or y (prefer x) * ``` * - * For more control over the output format, create a logger with a different handler. - * This statement uses [New] to create a new logger with a [TextHandler] - * that writes structured records in text form to standard error: + * Repetitions: * * ``` - * logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) + * x* zero or more x, prefer more + * x+ one or more x, prefer more + * x? zero or one x, prefer one + * x{n,m} n or n+1 or ... or m x, prefer more + * x{n,} n or more x, prefer more + * x{n} exactly n x + * x*? zero or more x, prefer fewer + * x+? one or more x, prefer fewer + * x?? zero or one x, prefer zero + * x{n,m}? n or n+1 or ... or m x, prefer fewer + * x{n,}? n or more x, prefer fewer + * x{n}? exactly n x * ``` * - * [TextHandler] output is a sequence of key=value pairs, easily and unambiguously - * parsed by machine. This statement: - * - * ``` - * logger.Info("hello", "count", 3) - * ``` + * Implementation restriction: The counting forms x{n,m}, x{n,}, and x{n} + * reject forms that create a minimum or maximum repetition count above 1000. + * Unlimited repetitions are not subject to this restriction. * - * produces this output: + * Grouping: * * ``` - * time=2022-11-08T15:28:26.000-05:00 level=INFO msg=hello count=3 - * ``` + * (re) numbered capturing group (submatch) + * (?Pre) named & numbered capturing group (submatch) + * (?re) named & numbered capturing group (submatch) + * (?:re) non-capturing group + * (?flags) set flags within current group; non-capturing + * (?flags:re) set flags during re; non-capturing * - * The package also provides [JSONHandler], whose output is line-delimited JSON: + * Flag syntax is xyz (set) or -xyz (clear) or xy-z (set xy, clear z). The flags are: * - * ``` - * logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) - * logger.Info("hello", "count", 3) + * i case-insensitive (default false) + * m multi-line mode: ^ and $ match begin/end line in addition to begin/end text (default false) + * s let . match \n (default false) + * U ungreedy: swap meaning of x* and x*?, x+ and x+?, etc (default false) * ``` * - * produces this output: + * Empty strings: * * ``` - * {"time":"2022-11-08T15:28:26.000000000-05:00","level":"INFO","msg":"hello","count":3} + * ^ at beginning of text or line (flag m=true) + * $ at end of text (like \z not \Z) or line (flag m=true) + * \A at beginning of text + * \b at ASCII word boundary (\w on one side and \W, \A, or \z on the other) + * \B not at ASCII word boundary + * \z at end of text * ``` * - * Both [TextHandler] and [JSONHandler] can be configured with [HandlerOptions]. - * There are options for setting the minimum level (see Levels, below), - * displaying the source file and line of the log call, and - * modifying attributes before they are logged. - * - * Setting a logger as the default with + * Escape sequences: * * ``` - * slog.SetDefault(logger) + * \a bell (== \007) + * \f form feed (== \014) + * \t horizontal tab (== \011) + * \n newline (== \012) + * \r carriage return (== \015) + * \v vertical tab character (== \013) + * \* literal *, for any punctuation character * + * \123 octal character code (up to three digits) + * \x7F hex character code (exactly two digits) + * \x{10FFFF} hex character code + * \Q...\E literal text ... even if ... has punctuation * ``` * - * will cause the top-level functions like [Info] to use it. - * [SetDefault] also updates the default logger used by the [log] package, - * so that existing applications that use [log.Printf] and related functions - * will send log records to the logger's handler without needing to be rewritten. - * - * Some attributes are common to many log calls. - * For example, you may wish to include the URL or trace identifier of a server request - * with all log events arising from the request. - * Rather than repeat the attribute with every log call, you can use [Logger.With] - * to construct a new Logger containing the attributes: + * Character class elements: * * ``` - * logger2 := logger.With("url", r.URL) + * x single character + * A-Z character range (inclusive) + * \d Perl character class + * [:foo:] ASCII character class foo + * \p{Foo} Unicode character class Foo + * \pF Unicode character class F (one-letter name) * ``` * - * The arguments to With are the same key-value pairs used in [Logger.Info]. - * The result is a new Logger with the same handler as the original, but additional - * attributes that will appear in the output of every call. - * - * # Levels - * - * A [Level] is an integer representing the importance or severity of a log event. - * The higher the level, the more severe the event. - * This package defines constants for the most common levels, - * but any int can be used as a level. - * - * In an application, you may wish to log messages only at a certain level or greater. - * One common configuration is to log messages at Info or higher levels, - * suppressing debug logging until it is needed. - * The built-in handlers can be configured with the minimum level to output by - * setting [HandlerOptions.Level]. - * The program's `main` function typically does this. - * The default value is LevelInfo. - * - * Setting the [HandlerOptions.Level] field to a [Level] value - * fixes the handler's minimum level throughout its lifetime. - * Setting it to a [LevelVar] allows the level to be varied dynamically. - * A LevelVar holds a Level and is safe to read or write from multiple - * goroutines. - * To vary the level dynamically for an entire program, first initialize - * a global LevelVar: + * Named character classes as character class elements: * * ``` - * var programLevel = new(slog.LevelVar) // Info by default + * [\d] digits (== \d) + * [^\d] not digits (== \D) + * [\D] not digits (== \D) + * [^\D] not not digits (== \d) + * [[:name:]] named ASCII class inside character class (== [:name:]) + * [^[:name:]] named ASCII class inside negated character class (== [:^name:]) + * [\p{Name}] named Unicode property inside character class (== \p{Name}) + * [^\p{Name}] named Unicode property inside negated character class (== \P{Name}) * ``` * - * Then use the LevelVar to construct a handler, and make it the default: + * Perl character classes (all ASCII-only): * * ``` - * h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}) - * slog.SetDefault(slog.New(h)) + * \d digits (== [0-9]) + * \D not digits (== [^0-9]) + * \s whitespace (== [\t\n\f\r ]) + * \S not whitespace (== [^\t\n\f\r ]) + * \w word characters (== [0-9A-Za-z_]) + * \W not word characters (== [^0-9A-Za-z_]) * ``` * - * Now the program can change its logging level with a single statement: + * ASCII character classes: * * ``` - * programLevel.Set(slog.LevelDebug) + * [[:alnum:]] alphanumeric (== [0-9A-Za-z]) + * [[:alpha:]] alphabetic (== [A-Za-z]) + * [[:ascii:]] ASCII (== [\x00-\x7F]) + * [[:blank:]] blank (== [\t ]) + * [[:cntrl:]] control (== [\x00-\x1F\x7F]) + * [[:digit:]] digits (== [0-9]) + * [[:graph:]] graphical (== [!-~] == [A-Za-z0-9!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]) + * [[:lower:]] lower case (== [a-z]) + * [[:print:]] printable (== [ -~] == [ [:graph:]]) + * [[:punct:]] punctuation (== [!-/:-@[-`{-~]) + * [[:space:]] whitespace (== [\t\n\v\f\r ]) + * [[:upper:]] upper case (== [A-Z]) + * [[:word:]] word characters (== [0-9A-Za-z_]) + * [[:xdigit:]] hex digit (== [0-9A-Fa-f]) * ``` * - * # Groups - * - * Attributes can be collected into groups. - * A group has a name that is used to qualify the names of its attributes. - * How this qualification is displayed depends on the handler. - * [TextHandler] separates the group and attribute names with a dot. - * [JSONHandler] treats each group as a separate JSON object, with the group name as the key. - * - * Use [Group] to create a Group attribute from a name and a list of key-value pairs: + * Unicode character classes are those in [unicode.Categories] and [unicode.Scripts]. + */ +namespace syntax { + /** + * Flags control the behavior of the parser and record information about regexp context. + */ + interface Flags extends Number{} +} + +/** + * Package net provides a portable interface for network I/O, including + * TCP/IP, UDP, domain name resolution, and Unix domain sockets. * - * ``` - * slog.Group("request", - * "method", r.Method, - * "url", r.URL) - * ``` + * Although the package provides access to low-level networking + * primitives, most clients will need only the basic interface provided + * by the [Dial], [Listen], and Accept functions and the associated + * [Conn] and [Listener] interfaces. The crypto/tls package uses + * the same interfaces and similar Dial and Listen functions. * - * TextHandler would display this group as + * The Dial function connects to a server: * * ``` - * request.method=GET request.url=http://example.com + * conn, err := net.Dial("tcp", "golang.org:80") + * if err != nil { + * // handle error + * } + * fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n") + * status, err := bufio.NewReader(conn).ReadString('\n') + * // ... * ``` * - * JSONHandler would display it as + * The Listen function creates servers: * * ``` - * "request":{"method":"GET","url":"http://example.com"} + * ln, err := net.Listen("tcp", ":8080") + * if err != nil { + * // handle error + * } + * for { + * conn, err := ln.Accept() + * if err != nil { + * // handle error + * } + * go handleConnection(conn) + * } * ``` * - * Use [Logger.WithGroup] to qualify all of a Logger's output - * with a group name. Calling WithGroup on a Logger results in a - * new Logger with the same Handler as the original, but with all - * its attributes qualified by the group name. - * - * This can help prevent duplicate attribute keys in large systems, - * where subsystems might use the same keys. - * Pass each subsystem a different Logger with its own group name so that - * potential duplicates are qualified: - * - * ``` - * logger := slog.Default().With("id", systemID) - * parserLogger := logger.WithGroup("parser") - * parseInput(input, parserLogger) - * ``` + * # Name Resolution * - * When parseInput logs with parserLogger, its keys will be qualified with "parser", - * so even if it uses the common key "id", the log line will have distinct keys. + * The method for resolving domain names, whether indirectly with functions like Dial + * or directly with functions like [LookupHost] and [LookupAddr], varies by operating system. * - * # Contexts + * On Unix systems, the resolver has two options for resolving names. + * It can use a pure Go resolver that sends DNS requests directly to the servers + * listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C + * library routines such as getaddrinfo and getnameinfo. * - * Some handlers may wish to include information from the [context.Context] that is - * available at the call site. One example of such information - * is the identifier for the current span when tracing is enabled. + * On Unix the pure Go resolver is preferred over the cgo resolver, because a blocked DNS + * request consumes only a goroutine, while a blocked C call consumes an operating system thread. + * When cgo is available, the cgo-based resolver is used instead under a variety of + * conditions: on systems that do not let programs make direct DNS requests (OS X), + * when the LOCALDOMAIN environment variable is present (even if empty), + * when the RES_OPTIONS or HOSTALIASES environment variable is non-empty, + * when the ASR_CONFIG environment variable is non-empty (OpenBSD only), + * when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the + * Go resolver does not implement. * - * The [Logger.Log] and [Logger.LogAttrs] methods take a context as a first - * argument, as do their corresponding top-level functions. + * On all systems (except Plan 9), when the cgo resolver is being used + * this package applies a concurrent cgo lookup limit to prevent the system + * from running out of system threads. Currently, it is limited to 500 concurrent lookups. * - * Although the convenience methods on Logger (Info and so on) and the - * corresponding top-level functions do not take a context, the alternatives ending - * in "Context" do. For example, + * The resolver decision can be overridden by setting the netdns value of the + * GODEBUG environment variable (see package runtime) to go or cgo, as in: * * ``` - * slog.InfoContext(ctx, "message") + * export GODEBUG=netdns=go # force pure Go resolver + * export GODEBUG=netdns=cgo # force native resolver (cgo, win32) * ``` * - * It is recommended to pass a context to an output method if one is available. + * The decision can also be forced while building the Go source tree + * by setting the netgo or netcgo build tag. + * The netgo build tag disables entirely the use of the native (CGO) resolver, + * meaning the Go resolver is the only one that can be used. + * With the netcgo build tag the native and the pure Go resolver are compiled into the binary, + * but the native (CGO) resolver is preferred over the Go resolver. + * With netcgo, the Go resolver can still be forced at runtime with GODEBUG=netdns=go. * - * # Attrs and Values + * A numeric netdns setting, as in GODEBUG=netdns=1, causes the resolver + * to print debugging information about its decisions. + * To force a particular resolver while also printing debugging information, + * join the two settings by a plus sign, as in GODEBUG=netdns=go+1. * - * An [Attr] is a key-value pair. The Logger output methods accept Attrs as well as - * alternating keys and values. The statement + * The Go resolver will send an EDNS0 additional header with a DNS request, + * to signal a willingness to accept a larger DNS packet size. + * This can reportedly cause sporadic failures with the DNS server run + * by some modems and routers. Setting GODEBUG=netedns0=0 will disable + * sending the additional header. * - * ``` - * slog.Info("hello", slog.Int("count", 3)) - * ``` - * - * behaves the same as - * - * ``` - * slog.Info("hello", "count", 3) - * ``` - * - * There are convenience constructors for [Attr] such as [Int], [String], and [Bool] - * for common types, as well as the function [Any] for constructing Attrs of any - * type. - * - * The value part of an Attr is a type called [Value]. - * Like an [any], a Value can hold any Go value, - * but it can represent typical values, including all numbers and strings, - * without an allocation. - * - * For the most efficient log output, use [Logger.LogAttrs]. - * It is similar to [Logger.Log] but accepts only Attrs, not alternating - * keys and values; this allows it, too, to avoid allocation. - * - * The call - * - * ``` - * logger.LogAttrs(ctx, slog.LevelInfo, "hello", slog.Int("count", 3)) - * ``` - * - * is the most efficient way to achieve the same output as - * - * ``` - * slog.InfoContext(ctx, "hello", "count", 3) - * ``` - * - * # Customizing a type's logging behavior - * - * If a type implements the [LogValuer] interface, the [Value] returned from its LogValue - * method is used for logging. You can use this to control how values of the type - * appear in logs. For example, you can redact secret information like passwords, - * or gather a struct's fields in a Group. See the examples under [LogValuer] for - * details. - * - * A LogValue method may return a Value that itself implements [LogValuer]. The [Value.Resolve] - * method handles these cases carefully, avoiding infinite loops and unbounded recursion. - * Handler authors and others may wish to use [Value.Resolve] instead of calling LogValue directly. - * - * # Wrapping output methods - * - * The logger functions use reflection over the call stack to find the file name - * and line number of the logging call within the application. This can produce - * incorrect source information for functions that wrap slog. For instance, if you - * define this function in file mylog.go: - * - * ``` - * func Infof(logger *slog.Logger, format string, args ...any) { - * logger.Info(fmt.Sprintf(format, args...)) - * } - * ``` - * - * and you call it like this in main.go: - * - * ``` - * Infof(slog.Default(), "hello, %s", "world") - * ``` - * - * then slog will report the source file as mylog.go, not main.go. - * - * A correct implementation of Infof will obtain the source location - * (pc) and pass it to NewRecord. - * The Infof function in the package-level example called "wrapping" - * demonstrates how to do this. - * - * # Working with Records - * - * Sometimes a Handler will need to modify a Record - * before passing it on to another Handler or backend. - * A Record contains a mixture of simple public fields (e.g. Time, Level, Message) - * and hidden fields that refer to state (such as attributes) indirectly. This - * means that modifying a simple copy of a Record (e.g. by calling - * [Record.Add] or [Record.AddAttrs] to add attributes) - * may have unexpected effects on the original. - * Before modifying a Record, use [Record.Clone] to - * create a copy that shares no state with the original, - * or create a new Record with [NewRecord] - * and build up its Attrs by traversing the old ones with [Record.Attrs]. - * - * # Performance considerations - * - * If profiling your application demonstrates that logging is taking significant time, - * the following suggestions may help. - * - * If many log lines have a common attribute, use [Logger.With] to create a Logger with - * that attribute. The built-in handlers will format that attribute only once, at the - * call to [Logger.With]. The [Handler] interface is designed to allow that optimization, - * and a well-written Handler should take advantage of it. - * - * The arguments to a log call are always evaluated, even if the log event is discarded. - * If possible, defer computation so that it happens only if the value is actually logged. - * For example, consider the call - * - * ``` - * slog.Info("starting request", "url", r.URL.String()) // may compute String unnecessarily - * ``` - * - * The URL.String method will be called even if the logger discards Info-level events. - * Instead, pass the URL directly: - * - * ``` - * slog.Info("starting request", "url", &r.URL) // calls URL.String only if needed - * ``` - * - * The built-in [TextHandler] will call its String method, but only - * if the log event is enabled. - * Avoiding the call to String also preserves the structure of the underlying value. - * For example [JSONHandler] emits the components of the parsed URL as a JSON object. - * If you want to avoid eagerly paying the cost of the String call - * without causing the handler to potentially inspect the structure of the value, - * wrap the value in a fmt.Stringer implementation that hides its Marshal methods. - * - * You can also use the [LogValuer] interface to avoid unnecessary work in disabled log - * calls. Say you need to log some expensive value: - * - * ``` - * slog.Debug("frobbing", "value", computeExpensiveValue(arg)) - * ``` - * - * Even if this line is disabled, computeExpensiveValue will be called. - * To avoid that, define a type implementing LogValuer: - * - * ``` - * type expensive struct { arg int } - * - * func (e expensive) LogValue() slog.Value { - * return slog.AnyValue(computeExpensiveValue(e.arg)) - * } - * ``` - * - * Then use a value of that type in log calls: - * - * ``` - * slog.Debug("frobbing", "value", expensive{arg}) - * ``` - * - * Now computeExpensiveValue will only be called when the line is enabled. - * - * The built-in handlers acquire a lock before calling [io.Writer.Write] - * to ensure that exactly one [Record] is written at a time in its entirety. - * Although each log record has a timestamp, - * the built-in handlers do not use that time to sort the written records. - * User-defined handlers are responsible for their own locking and sorting. + * On macOS, if Go code that uses the net package is built with + * -buildmode=c-archive, linking the resulting archive into a C program + * requires passing -lresolv when linking the C code. * - * # Writing a handler + * On Plan 9, the resolver always accesses /net/cs and /net/dns. * - * For a guide to writing a custom handler, see https://golang.org/s/slog-handler-guide. + * On Windows, in Go 1.18.x and earlier, the resolver always used C + * library functions, such as GetAddrInfo and DnsQuery. */ -namespace slog { - // @ts-ignore - import loginternal = internal +namespace net { /** - * A Logger records structured information about each call to its - * Log, Debug, Info, Warn, and Error methods. - * For each call, it creates a [Record] and passes it to a [Handler]. + * Conn is a generic stream-oriented network connection. * - * To create a new Logger, call [New] or a Logger method - * that begins "With". + * Multiple goroutines may invoke methods on a Conn simultaneously. */ - interface Logger { - } - interface Logger { + interface Conn { + [key:string]: any; /** - * Handler returns l's Handler. + * Read reads data from the connection. + * Read can be made to time out and return an error after a fixed + * time limit; see SetDeadline and SetReadDeadline. */ - handler(): Handler - } - interface Logger { + read(b: string|Array): number /** - * With returns a Logger that includes the given attributes - * in each output operation. Arguments are converted to - * attributes as if by [Logger.Log]. + * Write writes data to the connection. + * Write can be made to time out and return an error after a fixed + * time limit; see SetDeadline and SetWriteDeadline. */ - with(...args: any[]): (Logger) - } - interface Logger { + write(b: string|Array): number /** - * WithGroup returns a Logger that starts a group, if name is non-empty. - * The keys of all attributes added to the Logger will be qualified by the given - * name. (How that qualification happens depends on the [Handler.WithGroup] - * method of the Logger's Handler.) - * - * If name is empty, WithGroup returns the receiver. + * Close closes the connection. + * Any blocked Read or Write operations will be unblocked and return errors. */ - withGroup(name: string): (Logger) - } - interface Logger { + close(): void /** - * Enabled reports whether l emits log records at the given context and level. + * LocalAddr returns the local network address, if known. */ - enabled(ctx: context.Context, level: Level): boolean - } - interface Logger { + localAddr(): Addr /** - * Log emits a log record with the current time and the given level and message. - * The Record's Attrs consist of the Logger's attributes followed by - * the Attrs specified by args. - * - * The attribute arguments are processed as follows: - * ``` - * - If an argument is an Attr, it is used as is. - * - If an argument is a string and this is not the last argument, - * the following argument is treated as the value and the two are combined - * into an Attr. - * - Otherwise, the argument is treated as a value with key "!BADKEY". - * ``` + * RemoteAddr returns the remote network address, if known. */ - log(ctx: context.Context, level: Level, msg: string, ...args: any[]): void - } - interface Logger { + remoteAddr(): Addr /** - * LogAttrs is a more efficient version of [Logger.Log] that accepts only Attrs. + * SetDeadline sets the read and write deadlines associated + * with the connection. It is equivalent to calling both + * SetReadDeadline and SetWriteDeadline. + * + * A deadline is an absolute time after which I/O operations + * fail instead of blocking. The deadline applies to all future + * and pending I/O, not just the immediately following call to + * Read or Write. After a deadline has been exceeded, the + * connection can be refreshed by setting a deadline in the future. + * + * If the deadline is exceeded a call to Read or Write or to other + * I/O methods will return an error that wraps os.ErrDeadlineExceeded. + * This can be tested using errors.Is(err, os.ErrDeadlineExceeded). + * The error's Timeout method will return true, but note that there + * are other possible errors for which the Timeout method will + * return true even if the deadline has not been exceeded. + * + * An idle timeout can be implemented by repeatedly extending + * the deadline after successful Read or Write calls. + * + * A zero value for t means I/O operations will not time out. */ - logAttrs(ctx: context.Context, level: Level, msg: string, ...attrs: Attr[]): void - } - interface Logger { + setDeadline(t: time.Time): void /** - * Debug logs at [LevelDebug]. + * SetReadDeadline sets the deadline for future Read calls + * and any currently-blocked Read call. + * A zero value for t means Read will not time out. */ - debug(msg: string, ...args: any[]): void + setReadDeadline(t: time.Time): void + /** + * SetWriteDeadline sets the deadline for future Write calls + * and any currently-blocked Write call. + * Even if write times out, it may return n > 0, indicating that + * some of the data was successfully written. + * A zero value for t means Write will not time out. + */ + setWriteDeadline(t: time.Time): void } - interface Logger { + /** + * A Listener is a generic network listener for stream-oriented protocols. + * + * Multiple goroutines may invoke methods on a Listener simultaneously. + */ + interface Listener { + [key:string]: any; /** - * DebugContext logs at [LevelDebug] with the given context. + * Accept waits for and returns the next connection to the listener. */ - debugContext(ctx: context.Context, msg: string, ...args: any[]): void + accept(): Conn + /** + * Close closes the listener. + * Any blocked Accept operations will be unblocked and return errors. + */ + close(): void + /** + * Addr returns the listener's network address. + */ + addr(): Addr } - interface Logger { +} + +/** + * Package jwt is a Go implementation of JSON Web Tokens: http://self-issued.info/docs/draft-jones-json-web-token.html + * + * See README.md for more info. + */ +namespace jwt { + /** + * MapClaims is a claims type that uses the map[string]any for JSON + * decoding. This is the default claims type if you don't supply one + */ + interface MapClaims extends _TygojaDict{} + interface MapClaims { /** - * Info logs at [LevelInfo]. + * GetExpirationTime implements the Claims interface. */ - info(msg: string, ...args: any[]): void + getExpirationTime(): (NumericDate) } - interface Logger { + interface MapClaims { /** - * InfoContext logs at [LevelInfo] with the given context. + * GetNotBefore implements the Claims interface. */ - infoContext(ctx: context.Context, msg: string, ...args: any[]): void + getNotBefore(): (NumericDate) } - interface Logger { + interface MapClaims { /** - * Warn logs at [LevelWarn]. + * GetIssuedAt implements the Claims interface. */ - warn(msg: string, ...args: any[]): void + getIssuedAt(): (NumericDate) } - interface Logger { + interface MapClaims { /** - * WarnContext logs at [LevelWarn] with the given context. + * GetAudience implements the Claims interface. */ - warnContext(ctx: context.Context, msg: string, ...args: any[]): void + getAudience(): ClaimStrings } - interface Logger { + interface MapClaims { /** - * Error logs at [LevelError]. + * GetIssuer implements the Claims interface. */ - error(msg: string, ...args: any[]): void + getIssuer(): string } - interface Logger { + interface MapClaims { /** - * ErrorContext logs at [LevelError] with the given context. + * GetSubject implements the Claims interface. */ - errorContext(ctx: context.Context, msg: string, ...args: any[]): void + getSubject(): string } } -namespace subscriptions { +/** + * Package types implements some commonly used db serializable types + * like datetime, json, etc. + */ +namespace types { /** - * Broker defines a struct for managing subscriptions clients. + * DateTime represents a [time.Time] instance in UTC that is wrapped + * and serialized using the app default date layout. */ - interface Broker { + interface DateTime { } - interface Broker { + interface DateTime { /** - * Clients returns a shallow copy of all registered clients indexed - * with their connection id. + * Time returns the internal [time.Time] instance. */ - clients(): _TygojaDict + time(): time.Time } - interface Broker { + interface DateTime { /** - * ClientById finds a registered client by its id. - * - * Returns non-nil error when client with clientId is not registered. + * Add returns a new DateTime based on the current DateTime + the specified duration. */ - clientById(clientId: string): Client + add(duration: time.Duration): DateTime } - interface Broker { + interface DateTime { /** - * Register adds a new client to the broker instance. + * Sub returns a [time.Duration] by subtracting the specified DateTime from the current one. + * + * If the result exceeds the maximum (or minimum) value that can be stored in a [time.Duration], + * the maximum (or minimum) duration will be returned. */ - register(client: Client): void + sub(u: DateTime): time.Duration } - interface Broker { + interface DateTime { /** - * Unregister removes a single client by its id. + * AddDate returns a new DateTime based on the current one + duration. * - * If client with clientId doesn't exist, this method does nothing. + * It follows the same rules as [time.AddDate]. */ - unregister(clientId: string): void - } -} - -/** - * Package core is the backbone of PocketBase. - * - * It defines the main PocketBase App interface and its base implementation. - */ -namespace core { - interface BootstrapEvent { - app: App - } - interface TerminateEvent { - app: App - isRestart: boolean - } - interface ServeEvent { - app: App - router?: echo.Echo - server?: http.Server - certManager?: any + addDate(years: number, months: number, days: number): DateTime } - interface ApiErrorEvent { - httpContext: echo.Context - error: Error + interface DateTime { + /** + * After reports whether the current DateTime instance is after u. + */ + after(u: DateTime): boolean } - type _subCMPLw = BaseModelEvent - interface ModelEvent extends _subCMPLw { - dao?: daos.Dao + interface DateTime { + /** + * Before reports whether the current DateTime instance is before u. + */ + before(u: DateTime): boolean } - type _subCnFrG = BaseCollectionEvent - interface MailerRecordEvent extends _subCnFrG { - mailClient: mailer.Mailer - message?: mailer.Message - record?: models.Record - meta: _TygojaDict + interface DateTime { + /** + * Compare compares the current DateTime instance with u. + * If the current instance is before u, it returns -1. + * If the current instance is after u, it returns +1. + * If they're the same, it returns 0. + */ + compare(u: DateTime): number } - interface MailerAdminEvent { - mailClient: mailer.Mailer - message?: mailer.Message - admin?: models.Admin - meta: _TygojaDict + interface DateTime { + /** + * Equal reports whether the current DateTime and u represent the same time instant. + * Two DateTime can be equal even if they are in different locations. + * For example, 6:00 +0200 and 4:00 UTC are Equal. + */ + equal(u: DateTime): boolean } - interface RealtimeConnectEvent { - httpContext: echo.Context - client: subscriptions.Client - idleTimeout: time.Duration + interface DateTime { + /** + * Unix returns the current DateTime as a Unix time, aka. + * the number of seconds elapsed since January 1, 1970 UTC. + */ + unix(): number } - interface RealtimeDisconnectEvent { - httpContext: echo.Context - client: subscriptions.Client + interface DateTime { + /** + * IsZero checks whether the current DateTime instance has zero time value. + */ + isZero(): boolean } - interface RealtimeMessageEvent { - httpContext: echo.Context - client: subscriptions.Client - message?: subscriptions.Message + interface DateTime { + /** + * String serializes the current DateTime instance into a formatted + * UTC date string. + * + * The zero value is serialized to an empty string. + */ + string(): string } - interface RealtimeSubscribeEvent { - httpContext: echo.Context - client: subscriptions.Client - subscriptions: Array + interface DateTime { + /** + * MarshalJSON implements the [json.Marshaler] interface. + */ + marshalJSON(): string|Array } - interface SettingsListEvent { - httpContext: echo.Context - redactedSettings?: settings.Settings + interface DateTime { + /** + * UnmarshalJSON implements the [json.Unmarshaler] interface. + */ + unmarshalJSON(b: string|Array): void } - interface SettingsUpdateEvent { - httpContext: echo.Context - oldSettings?: settings.Settings - newSettings?: settings.Settings + interface DateTime { + /** + * Value implements the [driver.Valuer] interface. + */ + value(): any } - type _suboUOVp = BaseCollectionEvent - interface RecordsListEvent extends _suboUOVp { - httpContext: echo.Context - records: Array<(models.Record | undefined)> - result?: search.Result + interface DateTime { + /** + * Scan implements [sql.Scanner] interface to scan the provided value + * into the current DateTime instance. + */ + scan(value: any): void } - type _subMmDXk = BaseCollectionEvent - interface RecordViewEvent extends _subMmDXk { - httpContext: echo.Context - record?: models.Record - } - type _subTZYKy = BaseCollectionEvent - interface RecordCreateEvent extends _subTZYKy { - httpContext: echo.Context - record?: models.Record - uploadedFiles: _TygojaDict - } - type _subUPnol = BaseCollectionEvent - interface RecordUpdateEvent extends _subUPnol { - httpContext: echo.Context - record?: models.Record - uploadedFiles: _TygojaDict - } - type _subsOVxt = BaseCollectionEvent - interface RecordDeleteEvent extends _subsOVxt { - httpContext: echo.Context - record?: models.Record - } - type _subdOcOX = BaseCollectionEvent - interface RecordAuthEvent extends _subdOcOX { - httpContext: echo.Context - record?: models.Record - token: string - meta: any + /** + * GeoPoint defines a struct for storing geo coordinates as serialized json object + * (e.g. {lon:0,lat:0}). + * + * Note: using object notation and not a plain array to avoid the confusion + * as there doesn't seem to be a fixed standard for the coordinates order. + */ + interface GeoPoint { + lon: number + lat: number } - type _subcXjwK = BaseCollectionEvent - interface RecordAuthWithPasswordEvent extends _subcXjwK { - httpContext: echo.Context - record?: models.Record - identity: string - password: string + interface GeoPoint { + /** + * String returns the string representation of the current GeoPoint instance. + */ + string(): string } - type _sublULwe = BaseCollectionEvent - interface RecordAuthWithOAuth2Event extends _sublULwe { - httpContext: echo.Context - providerName: string - providerClient: auth.Provider - record?: models.Record - oAuth2User?: auth.AuthUser - isNewRecord: boolean + interface GeoPoint { + /** + * AsMap implements [core.mapExtractor] and returns a value suitable + * to be used in an API rule expression. + */ + asMap(): _TygojaDict } - type _subyEweS = BaseCollectionEvent - interface RecordAuthRefreshEvent extends _subyEweS { - httpContext: echo.Context - record?: models.Record - } - type _subGmfhi = BaseCollectionEvent - interface RecordRequestPasswordResetEvent extends _subGmfhi { - httpContext: echo.Context - record?: models.Record - } - type _subWgKmP = BaseCollectionEvent - interface RecordConfirmPasswordResetEvent extends _subWgKmP { - httpContext: echo.Context - record?: models.Record - } - type _subboQDs = BaseCollectionEvent - interface RecordRequestVerificationEvent extends _subboQDs { - httpContext: echo.Context - record?: models.Record - } - type _subRQkZq = BaseCollectionEvent - interface RecordConfirmVerificationEvent extends _subRQkZq { - httpContext: echo.Context - record?: models.Record - } - type _subCaQdu = BaseCollectionEvent - interface RecordRequestEmailChangeEvent extends _subCaQdu { - httpContext: echo.Context - record?: models.Record - } - type _subFeIqN = BaseCollectionEvent - interface RecordConfirmEmailChangeEvent extends _subFeIqN { - httpContext: echo.Context - record?: models.Record - } - type _subQtoYq = BaseCollectionEvent - interface RecordListExternalAuthsEvent extends _subQtoYq { - httpContext: echo.Context - record?: models.Record - externalAuths: Array<(models.ExternalAuth | undefined)> - } - type _subdbjaN = BaseCollectionEvent - interface RecordUnlinkExternalAuthEvent extends _subdbjaN { - httpContext: echo.Context - record?: models.Record - externalAuth?: models.ExternalAuth - } - interface AdminsListEvent { - httpContext: echo.Context - admins: Array<(models.Admin | undefined)> - result?: search.Result + interface GeoPoint { + /** + * Value implements the [driver.Valuer] interface. + */ + value(): any } - interface AdminViewEvent { - httpContext: echo.Context - admin?: models.Admin + interface GeoPoint { + /** + * Scan implements [sql.Scanner] interface to scan the provided value + * into the current GeoPoint instance. + * + * The value argument could be nil (no-op), another GeoPoint instance, + * map or serialized json object with lat-lon props. + */ + scan(value: any): void } - interface AdminCreateEvent { - httpContext: echo.Context - admin?: models.Admin + /** + * JSONArray defines a slice that is safe for json and db read/write. + */ + interface JSONArray extends Array{} + interface JSONArray { + /** + * MarshalJSON implements the [json.Marshaler] interface. + */ + marshalJSON(): string|Array } - interface AdminUpdateEvent { - httpContext: echo.Context - admin?: models.Admin + interface JSONArray { + /** + * String returns the string representation of the current json array. + */ + string(): string } - interface AdminDeleteEvent { - httpContext: echo.Context - admin?: models.Admin + interface JSONArray { + /** + * Value implements the [driver.Valuer] interface. + */ + value(): any } - interface AdminAuthEvent { - httpContext: echo.Context - admin?: models.Admin - token: string + interface JSONArray { + /** + * Scan implements [sql.Scanner] interface to scan the provided value + * into the current JSONArray[T] instance. + */ + scan(value: any): void } - interface AdminAuthWithPasswordEvent { - httpContext: echo.Context - admin?: models.Admin - identity: string - password: string + /** + * JSONMap defines a map that is safe for json and db read/write. + */ + interface JSONMap extends _TygojaDict{} + interface JSONMap { + /** + * MarshalJSON implements the [json.Marshaler] interface. + */ + marshalJSON(): string|Array } - interface AdminAuthRefreshEvent { - httpContext: echo.Context - admin?: models.Admin + interface JSONMap { + /** + * String returns the string representation of the current json map. + */ + string(): string } - interface AdminRequestPasswordResetEvent { - httpContext: echo.Context - admin?: models.Admin + interface JSONMap { + /** + * Get retrieves a single value from the current JSONMap[T]. + * + * This helper was added primarily to assist the goja integration since custom map types + * don't have direct access to the map keys (https://pkg.go.dev/github.com/dop251/goja#hdr-Maps_with_methods). + */ + get(key: string): T } - interface AdminConfirmPasswordResetEvent { - httpContext: echo.Context - admin?: models.Admin + interface JSONMap { + /** + * Set sets a single value in the current JSONMap[T]. + * + * This helper was added primarily to assist the goja integration since custom map types + * don't have direct access to the map keys (https://pkg.go.dev/github.com/dop251/goja#hdr-Maps_with_methods). + */ + set(key: string, value: T): void } - interface CollectionsListEvent { - httpContext: echo.Context - collections: Array<(models.Collection | undefined)> - result?: search.Result + interface JSONMap { + /** + * Value implements the [driver.Valuer] interface. + */ + value(): any } - type _subgEACr = BaseCollectionEvent - interface CollectionViewEvent extends _subgEACr { - httpContext: echo.Context + interface JSONMap { + /** + * Scan implements [sql.Scanner] interface to scan the provided value + * into the current JSONMap[T] instance. + */ + scan(value: any): void } - type _subQmWZW = BaseCollectionEvent - interface CollectionCreateEvent extends _subQmWZW { - httpContext: echo.Context - } - type _subWgIts = BaseCollectionEvent - interface CollectionUpdateEvent extends _subWgIts { - httpContext: echo.Context + /** + * JSONRaw defines a json value type that is safe for db read/write. + */ + interface JSONRaw extends Array{} + interface JSONRaw { + /** + * String returns the current JSONRaw instance as a json encoded string. + */ + string(): string } - type _subwJThk = BaseCollectionEvent - interface CollectionDeleteEvent extends _subwJThk { - httpContext: echo.Context + interface JSONRaw { + /** + * MarshalJSON implements the [json.Marshaler] interface. + */ + marshalJSON(): string|Array } - interface CollectionsImportEvent { - httpContext: echo.Context - collections: Array<(models.Collection | undefined)> + interface JSONRaw { + /** + * UnmarshalJSON implements the [json.Unmarshaler] interface. + */ + unmarshalJSON(b: string|Array): void } - type _subrFRLX = BaseModelEvent - interface FileTokenEvent extends _subrFRLX { - httpContext: echo.Context - token: string + interface JSONRaw { + /** + * Value implements the [driver.Valuer] interface. + */ + value(): any } - type _subQDQbp = BaseCollectionEvent - interface FileDownloadEvent extends _subQDQbp { - httpContext: echo.Context - record?: models.Record - fileField?: schema.SchemaField - servedPath: string - servedName: string + interface JSONRaw { + /** + * Scan implements [sql.Scanner] interface to scan the provided value + * into the current JSONRaw instance. + */ + scan(value: any): void } } -/** - * Package cobra is a commander providing a simple interface to create powerful modern CLI interfaces. - * In addition to providing an interface, Cobra simultaneously provides a controller to organize your application code. - */ -namespace cobra { - interface PositionalArgs {(cmd: Command, args: Array): void } - // @ts-ignore - import flag = pflag - /** - * FParseErrWhitelist configures Flag parse errors to be ignored - */ - interface FParseErrWhitelist extends _TygojaAny{} +namespace search { /** - * Group Structure to manage groups for commands + * Result defines the returned search result structure. */ - interface Group { - id: string - title: string + interface Result { + items: any + page: number + perPage: number + totalItems: number + totalPages: number } /** - * ShellCompDirective is a bit map representing the different behaviors the shell - * can be instructed to have once completions have been provided. - */ - interface ShellCompDirective extends Number{} - /** - * CompletionOptions are the options to control shell completion + * ResolverResult defines a single FieldResolver.Resolve() successfully parsed result. */ - interface CompletionOptions { + interface ResolverResult { /** - * DisableDefaultCmd prevents Cobra from creating a default 'completion' command + * Identifier is the plain SQL identifier/column that will be used + * in the final db expression as left or right operand. */ - disableDefaultCmd: boolean + identifier: string /** - * DisableNoDescFlag prevents Cobra from creating the '--no-descriptions' flag - * for shells that support completion descriptions + * NoCoalesce instructs to not use COALESCE or NULL fallbacks + * when building the identifier expression. */ - disableNoDescFlag: boolean + noCoalesce: boolean /** - * DisableDescriptions turns off all completion descriptions for shells - * that support them + * Params is a map with db placeholder->value pairs that will be added + * to the query when building both resolved operands/sides in a single expression. */ - disableDescriptions: boolean + params: dbx.Params /** - * HiddenDefaultCmd makes the default 'completion' command hidden + * MultiMatchSubQuery is an optional sub query expression that will be added + * in addition to the combined ResolverResult expression during build. */ - hiddenDefaultCmd: boolean - } -} - -namespace migrate { - interface Migration { - file: string - up: (db: dbx.Builder) => void - down: (db: dbx.Builder) => void - } -} - -/** - * Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer - * object, creating another object (Reader or Writer) that also implements - * the interface but provides buffering and some help for textual I/O. - */ -namespace bufio { - /** - * ReadWriter stores pointers to a [Reader] and a [Writer]. - * It implements [io.ReadWriter]. - */ - type _subLmeyk = Reader&Writer - interface ReadWriter extends _subLmeyk { + multiMatchSubQuery: dbx.Expression + /** + * AfterBuild is an optional function that will be called after building + * and combining the result of both resolved operands/sides in a single expression. + */ + afterBuild: (expr: dbx.Expression) => dbx.Expression } } /** - * Package net provides a portable interface for network I/O, including - * TCP/IP, UDP, domain name resolution, and Unix domain sockets. + * Package slog provides structured logging, + * in which log records include a message, + * a severity level, and various other attributes + * expressed as key-value pairs. * - * Although the package provides access to low-level networking - * primitives, most clients will need only the basic interface provided - * by the [Dial], [Listen], and Accept functions and the associated - * [Conn] and [Listener] interfaces. The crypto/tls package uses - * the same interfaces and similar Dial and Listen functions. + * It defines a type, [Logger], + * which provides several methods (such as [Logger.Info] and [Logger.Error]) + * for reporting events of interest. * - * The Dial function connects to a server: + * Each Logger is associated with a [Handler]. + * A Logger output method creates a [Record] from the method arguments + * and passes it to the Handler, which decides how to handle it. + * There is a default Logger accessible through top-level functions + * (such as [Info] and [Error]) that call the corresponding Logger methods. + * + * A log record consists of a time, a level, a message, and a set of key-value + * pairs, where the keys are strings and the values may be of any type. + * As an example, * * ``` - * conn, err := net.Dial("tcp", "golang.org:80") - * if err != nil { - * // handle error - * } - * fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n") - * status, err := bufio.NewReader(conn).ReadString('\n') - * // ... + * slog.Info("hello", "count", 3) * ``` * - * The Listen function creates servers: + * creates a record containing the time of the call, + * a level of Info, the message "hello", and a single + * pair with key "count" and value 3. + * + * The [Info] top-level function calls the [Logger.Info] method on the default Logger. + * In addition to [Logger.Info], there are methods for Debug, Warn and Error levels. + * Besides these convenience methods for common levels, + * there is also a [Logger.Log] method which takes the level as an argument. + * Each of these methods has a corresponding top-level function that uses the + * default logger. + * + * The default handler formats the log record's message, time, level, and attributes + * as a string and passes it to the [log] package. * * ``` - * ln, err := net.Listen("tcp", ":8080") - * if err != nil { - * // handle error - * } - * for { - * conn, err := ln.Accept() - * if err != nil { - * // handle error - * } - * go handleConnection(conn) - * } + * 2022/11/08 15:28:26 INFO hello count=3 * ``` * - * # Name Resolution + * For more control over the output format, create a logger with a different handler. + * This statement uses [New] to create a new logger with a [TextHandler] + * that writes structured records in text form to standard error: * - * The method for resolving domain names, whether indirectly with functions like Dial - * or directly with functions like [LookupHost] and [LookupAddr], varies by operating system. + * ``` + * logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) + * ``` * - * On Unix systems, the resolver has two options for resolving names. - * It can use a pure Go resolver that sends DNS requests directly to the servers - * listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C - * library routines such as getaddrinfo and getnameinfo. + * [TextHandler] output is a sequence of key=value pairs, easily and unambiguously + * parsed by machine. This statement: * - * On Unix the pure Go resolver is preferred over the cgo resolver, because a blocked DNS - * request consumes only a goroutine, while a blocked C call consumes an operating system thread. - * When cgo is available, the cgo-based resolver is used instead under a variety of - * conditions: on systems that do not let programs make direct DNS requests (OS X), - * when the LOCALDOMAIN environment variable is present (even if empty), - * when the RES_OPTIONS or HOSTALIASES environment variable is non-empty, - * when the ASR_CONFIG environment variable is non-empty (OpenBSD only), - * when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the - * Go resolver does not implement. + * ``` + * logger.Info("hello", "count", 3) + * ``` * - * On all systems (except Plan 9), when the cgo resolver is being used - * this package applies a concurrent cgo lookup limit to prevent the system - * from running out of system threads. Currently, it is limited to 500 concurrent lookups. + * produces this output: * - * The resolver decision can be overridden by setting the netdns value of the - * GODEBUG environment variable (see package runtime) to go or cgo, as in: + * ``` + * time=2022-11-08T15:28:26.000-05:00 level=INFO msg=hello count=3 + * ``` + * + * The package also provides [JSONHandler], whose output is line-delimited JSON: * * ``` - * export GODEBUG=netdns=go # force pure Go resolver - * export GODEBUG=netdns=cgo # force native resolver (cgo, win32) + * logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) + * logger.Info("hello", "count", 3) * ``` * - * The decision can also be forced while building the Go source tree - * by setting the netgo or netcgo build tag. + * produces this output: * - * A numeric netdns setting, as in GODEBUG=netdns=1, causes the resolver - * to print debugging information about its decisions. - * To force a particular resolver while also printing debugging information, - * join the two settings by a plus sign, as in GODEBUG=netdns=go+1. + * ``` + * {"time":"2022-11-08T15:28:26.000000000-05:00","level":"INFO","msg":"hello","count":3} + * ``` * - * The Go resolver will send an EDNS0 additional header with a DNS request, - * to signal a willingness to accept a larger DNS packet size. - * This can reportedly cause sporadic failures with the DNS server run - * by some modems and routers. Setting GODEBUG=netedns0=0 will disable - * sending the additional header. + * Both [TextHandler] and [JSONHandler] can be configured with [HandlerOptions]. + * There are options for setting the minimum level (see Levels, below), + * displaying the source file and line of the log call, and + * modifying attributes before they are logged. * - * On macOS, if Go code that uses the net package is built with - * -buildmode=c-archive, linking the resulting archive into a C program - * requires passing -lresolv when linking the C code. + * Setting a logger as the default with * - * On Plan 9, the resolver always accesses /net/cs and /net/dns. + * ``` + * slog.SetDefault(logger) + * ``` * - * On Windows, in Go 1.18.x and earlier, the resolver always used C - * library functions, such as GetAddrInfo and DnsQuery. - */ -namespace net { - /** - * Addr represents a network end point address. - * - * The two methods [Addr.Network] and [Addr.String] conventionally return strings - * that can be passed as the arguments to [Dial], but the exact form - * and meaning of the strings is up to the implementation. - */ - interface Addr { - [key:string]: any; - network(): string // name of the network (for example, "tcp", "udp") - string(): string // string form of address (for example, "192.0.2.1:25", "[2001:db8::1]:80") - } -} - -/** - * Package url parses URLs and implements query escaping. - */ -namespace url { - /** - * The Userinfo type is an immutable encapsulation of username and - * password details for a [URL]. An existing Userinfo value is guaranteed - * to have a username set (potentially empty, as allowed by RFC 2396), - * and optionally a password. - */ - interface Userinfo { - } - interface Userinfo { - /** - * Username returns the username. - */ - username(): string - } - interface Userinfo { - /** - * Password returns the password in case it is set, and whether it is set. - */ - password(): [string, boolean] - } - interface Userinfo { - /** - * String returns the encoded userinfo information in the standard form - * of "username[:password]". - */ - string(): string - } -} - -/** - * Package multipart implements MIME multipart parsing, as defined in RFC - * 2046. + * will cause the top-level functions like [Info] to use it. + * [SetDefault] also updates the default logger used by the [log] package, + * so that existing applications that use [log.Printf] and related functions + * will send log records to the logger's handler without needing to be rewritten. * - * The implementation is sufficient for HTTP (RFC 2388) and the multipart - * bodies generated by popular browsers. + * Some attributes are common to many log calls. + * For example, you may wish to include the URL or trace identifier of a server request + * with all log events arising from the request. + * Rather than repeat the attribute with every log call, you can use [Logger.With] + * to construct a new Logger containing the attributes: * - * # Limits + * ``` + * logger2 := logger.With("url", r.URL) + * ``` * - * To protect against malicious inputs, this package sets limits on the size - * of the MIME data it processes. + * The arguments to With are the same key-value pairs used in [Logger.Info]. + * The result is a new Logger with the same handler as the original, but additional + * attributes that will appear in the output of every call. * - * [Reader.NextPart] and [Reader.NextRawPart] limit the number of headers in a - * part to 10000 and [Reader.ReadForm] limits the total number of headers in all - * FileHeaders to 10000. - * These limits may be adjusted with the GODEBUG=multipartmaxheaders= - * setting. + * # Levels * - * Reader.ReadForm further limits the number of parts in a form to 1000. - * This limit may be adjusted with the GODEBUG=multipartmaxparts= - * setting. - */ -namespace multipart { - /** - * A Part represents a single part in a multipart body. - */ - interface Part { - /** - * The headers of the body, if any, with the keys canonicalized - * in the same fashion that the Go http.Request headers are. - * For example, "foo-bar" changes case to "Foo-Bar" - */ - header: textproto.MIMEHeader - } - interface Part { - /** - * FormName returns the name parameter if p has a Content-Disposition - * of type "form-data". Otherwise it returns the empty string. - */ - formName(): string - } - interface Part { - /** - * FileName returns the filename parameter of the [Part]'s Content-Disposition - * header. If not empty, the filename is passed through filepath.Base (which is - * platform dependent) before being returned. - */ - fileName(): string - } - interface Part { - /** - * Read reads the body of a part, after its headers and before the - * next part (if any) begins. - */ - read(d: string|Array): number - } - interface Part { - close(): void - } -} - -/** - * Package http provides HTTP client and server implementations. + * A [Level] is an integer representing the importance or severity of a log event. + * The higher the level, the more severe the event. + * This package defines constants for the most common levels, + * but any int can be used as a level. * - * [Get], [Head], [Post], and [PostForm] make HTTP (or HTTPS) requests: + * In an application, you may wish to log messages only at a certain level or greater. + * One common configuration is to log messages at Info or higher levels, + * suppressing debug logging until it is needed. + * The built-in handlers can be configured with the minimum level to output by + * setting [HandlerOptions.Level]. + * The program's `main` function typically does this. + * The default value is LevelInfo. + * + * Setting the [HandlerOptions.Level] field to a [Level] value + * fixes the handler's minimum level throughout its lifetime. + * Setting it to a [LevelVar] allows the level to be varied dynamically. + * A LevelVar holds a Level and is safe to read or write from multiple + * goroutines. + * To vary the level dynamically for an entire program, first initialize + * a global LevelVar: * * ``` - * resp, err := http.Get("http://example.com/") - * ... - * resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf) - * ... - * resp, err := http.PostForm("http://example.com/form", - * url.Values{"key": {"Value"}, "id": {"123"}}) + * var programLevel = new(slog.LevelVar) // Info by default * ``` * - * The caller must close the response body when finished with it: + * Then use the LevelVar to construct a handler, and make it the default: * * ``` - * resp, err := http.Get("http://example.com/") - * if err != nil { - * // handle error - * } - * defer resp.Body.Close() - * body, err := io.ReadAll(resp.Body) - * // ... + * h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}) + * slog.SetDefault(slog.New(h)) * ``` * - * # Clients and Transports + * Now the program can change its logging level with a single statement: * - * For control over HTTP client headers, redirect policy, and other - * settings, create a [Client]: + * ``` + * programLevel.Set(slog.LevelDebug) + * ``` + * + * # Groups + * + * Attributes can be collected into groups. + * A group has a name that is used to qualify the names of its attributes. + * How this qualification is displayed depends on the handler. + * [TextHandler] separates the group and attribute names with a dot. + * [JSONHandler] treats each group as a separate JSON object, with the group name as the key. + * + * Use [Group] to create a Group attribute from a name and a list of key-value pairs: * * ``` - * client := &http.Client{ - * CheckRedirect: redirectPolicyFunc, - * } + * slog.Group("request", + * "method", r.Method, + * "url", r.URL) + * ``` * - * resp, err := client.Get("http://example.com") - * // ... + * TextHandler would display this group as * - * req, err := http.NewRequest("GET", "http://example.com", nil) - * // ... - * req.Header.Add("If-None-Match", `W/"wyzzy"`) - * resp, err := client.Do(req) - * // ... + * ``` + * request.method=GET request.url=http://example.com * ``` * - * For control over proxies, TLS configuration, keep-alives, - * compression, and other settings, create a [Transport]: + * JSONHandler would display it as * * ``` - * tr := &http.Transport{ - * MaxIdleConns: 10, - * IdleConnTimeout: 30 * time.Second, - * DisableCompression: true, - * } - * client := &http.Client{Transport: tr} - * resp, err := client.Get("https://example.com") + * "request":{"method":"GET","url":"http://example.com"} * ``` * - * Clients and Transports are safe for concurrent use by multiple - * goroutines and for efficiency should only be created once and re-used. + * Use [Logger.WithGroup] to qualify all of a Logger's output + * with a group name. Calling WithGroup on a Logger results in a + * new Logger with the same Handler as the original, but with all + * its attributes qualified by the group name. * - * # Servers + * This can help prevent duplicate attribute keys in large systems, + * where subsystems might use the same keys. + * Pass each subsystem a different Logger with its own group name so that + * potential duplicates are qualified: * - * ListenAndServe starts an HTTP server with a given address and handler. - * The handler is usually nil, which means to use [DefaultServeMux]. - * [Handle] and [HandleFunc] add handlers to [DefaultServeMux]: + * ``` + * logger := slog.Default().With("id", systemID) + * parserLogger := logger.WithGroup("parser") + * parseInput(input, parserLogger) + * ``` + * + * When parseInput logs with parserLogger, its keys will be qualified with "parser", + * so even if it uses the common key "id", the log line will have distinct keys. + * + * # Contexts + * + * Some handlers may wish to include information from the [context.Context] that is + * available at the call site. One example of such information + * is the identifier for the current span when tracing is enabled. + * + * The [Logger.Log] and [Logger.LogAttrs] methods take a context as a first + * argument, as do their corresponding top-level functions. + * + * Although the convenience methods on Logger (Info and so on) and the + * corresponding top-level functions do not take a context, the alternatives ending + * in "Context" do. For example, * * ``` - * http.Handle("/foo", fooHandler) + * slog.InfoContext(ctx, "message") + * ``` * - * http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { - * fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) - * }) + * It is recommended to pass a context to an output method if one is available. * - * log.Fatal(http.ListenAndServe(":8080", nil)) + * # Attrs and Values + * + * An [Attr] is a key-value pair. The Logger output methods accept Attrs as well as + * alternating keys and values. The statement + * + * ``` + * slog.Info("hello", slog.Int("count", 3)) * ``` * - * More control over the server's behavior is available by creating a - * custom Server: + * behaves the same as * * ``` - * s := &http.Server{ - * Addr: ":8080", - * Handler: myHandler, - * ReadTimeout: 10 * time.Second, - * WriteTimeout: 10 * time.Second, - * MaxHeaderBytes: 1 << 20, - * } - * log.Fatal(s.ListenAndServe()) + * slog.Info("hello", "count", 3) * ``` * - * # HTTP/2 + * There are convenience constructors for [Attr] such as [Int], [String], and [Bool] + * for common types, as well as the function [Any] for constructing Attrs of any + * type. * - * Starting with Go 1.6, the http package has transparent support for the - * HTTP/2 protocol when using HTTPS. Programs that must disable HTTP/2 - * can do so by setting [Transport.TLSNextProto] (for clients) or - * [Server.TLSNextProto] (for servers) to a non-nil, empty - * map. Alternatively, the following GODEBUG settings are - * currently supported: + * The value part of an Attr is a type called [Value]. + * Like an [any], a Value can hold any Go value, + * but it can represent typical values, including all numbers and strings, + * without an allocation. + * + * For the most efficient log output, use [Logger.LogAttrs]. + * It is similar to [Logger.Log] but accepts only Attrs, not alternating + * keys and values; this allows it, too, to avoid allocation. + * + * The call * * ``` - * GODEBUG=http2client=0 # disable HTTP/2 client support - * GODEBUG=http2server=0 # disable HTTP/2 server support - * GODEBUG=http2debug=1 # enable verbose HTTP/2 debug logs - * GODEBUG=http2debug=2 # ... even more verbose, with frame dumps + * logger.LogAttrs(ctx, slog.LevelInfo, "hello", slog.Int("count", 3)) * ``` * - * Please report any issues before disabling HTTP/2 support: https://golang.org/s/http2bug + * is the most efficient way to achieve the same output as * - * The http package's [Transport] and [Server] both automatically enable - * HTTP/2 support for simple configurations. To enable HTTP/2 for more - * complex configurations, to use lower-level HTTP/2 features, or to use - * a newer version of Go's http2 package, import "golang.org/x/net/http2" - * directly and use its ConfigureTransport and/or ConfigureServer - * functions. Manually configuring HTTP/2 via the golang.org/x/net/http2 - * package takes precedence over the net/http package's built-in HTTP/2 - * support. - */ -namespace http { - /** - * SameSite allows a server to define a cookie attribute making it impossible for - * the browser to send this cookie along with cross-site requests. The main - * goal is to mitigate the risk of cross-origin information leakage, and provide - * some protection against cross-site request forgery attacks. - * - * See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details. - */ - interface SameSite extends Number{} - // @ts-ignore - import mathrand = rand - // @ts-ignore - import urlpkg = url -} - -/** - * Package types implements some commonly used db serializable types - * like datetime, json, etc. - */ -namespace types { - /** - * JsonRaw defines a json value type that is safe for db read/write. - */ - interface JsonRaw extends Array{} - interface JsonRaw { - /** - * String returns the current JsonRaw instance as a json encoded string. - */ - string(): string - } - interface JsonRaw { - /** - * MarshalJSON implements the [json.Marshaler] interface. - */ - marshalJSON(): string|Array - } - interface JsonRaw { - /** - * UnmarshalJSON implements the [json.Unmarshaler] interface. - */ - unmarshalJSON(b: string|Array): void - } - interface JsonRaw { - /** - * Value implements the [driver.Valuer] interface. - */ - value(): any - } - interface JsonRaw { - /** - * Scan implements [sql.Scanner] interface to scan the provided value - * into the current JsonRaw instance. - */ - scan(value: any): void - } -} - -namespace store { -} - -namespace search { - /** - * Result defines the returned search result structure. - */ - interface Result { - page: number - perPage: number - totalItems: number - totalPages: number - items: any - } -} - -namespace mailer { - /** - * Message defines a generic email message struct. - */ - interface Message { - from: mail.Address - to: Array - bcc: Array - cc: Array - subject: string - html: string - text: string - headers: _TygojaDict - attachments: _TygojaDict - } -} - -/** - * Package echo implements high performance, minimalist Go web framework. + * ``` + * slog.InfoContext(ctx, "hello", "count", 3) + * ``` * - * Example: + * # Customizing a type's logging behavior * - * ``` - * package main + * If a type implements the [LogValuer] interface, the [Value] returned from its LogValue + * method is used for logging. You can use this to control how values of the type + * appear in logs. For example, you can redact secret information like passwords, + * or gather a struct's fields in a Group. See the examples under [LogValuer] for + * details. * - * import ( - * "github.com/labstack/echo/v5" - * "github.com/labstack/echo/v5/middleware" - * "log" - * "net/http" - * ) + * A LogValue method may return a Value that itself implements [LogValuer]. The [Value.Resolve] + * method handles these cases carefully, avoiding infinite loops and unbounded recursion. + * Handler authors and others may wish to use [Value.Resolve] instead of calling LogValue directly. * - * // Handler - * func hello(c echo.Context) error { - * return c.String(http.StatusOK, "Hello, World!") - * } + * # Wrapping output methods * - * func main() { - * // Echo instance - * e := echo.New() + * The logger functions use reflection over the call stack to find the file name + * and line number of the logging call within the application. This can produce + * incorrect source information for functions that wrap slog. For instance, if you + * define this function in file mylog.go: * - * // Middleware - * e.Use(middleware.Logger()) - * e.Use(middleware.Recover()) + * ``` + * func Infof(logger *slog.Logger, format string, args ...any) { + * logger.Info(fmt.Sprintf(format, args...)) + * } + * ``` * - * // Routes - * e.GET("/", hello) + * and you call it like this in main.go: * - * // Start server - * if err := e.Start(":8080"); err != http.ErrServerClosed { - * log.Fatal(err) - * } - * } + * ``` + * Infof(slog.Default(), "hello, %s", "world") * ``` * - * Learn more at https://echo.labstack.com - */ -namespace echo { - // @ts-ignore - import stdContext = context - /** - * Route contains information to adding/registering new route with the router. - * Method+Path pair uniquely identifies the Route. It is mandatory to provide Method+Path+Handler fields. - */ - interface Route { - method: string - path: string - handler: HandlerFunc - middlewares: Array - name: string - } - interface Route { - /** - * ToRouteInfo converts Route to RouteInfo - */ - toRouteInfo(params: Array): RouteInfo - } - interface Route { - /** - * ToRoute returns Route which Router uses to register the method handler for path. - */ - toRoute(): Route - } - interface Route { - /** - * ForGroup recreates Route with added group prefix and group middlewares it is grouped to. - */ - forGroup(pathPrefix: string, middlewares: Array): Routable - } - /** - * RoutableContext is additional interface that structures implementing Context must implement. Methods inside this - * interface are meant for request routing purposes and should not be used in middlewares. - */ - interface RoutableContext { - [key:string]: any; - /** - * Request returns `*http.Request`. - */ - request(): (http.Request) - /** - * RawPathParams returns raw path pathParams value. Allocation of PathParams is handled by Context. - */ - rawPathParams(): (PathParams) - /** - * SetRawPathParams replaces any existing param values with new values for this context lifetime (request). - * Do not set any other value than what you got from RawPathParams as allocation of PathParams is handled by Context. - */ - setRawPathParams(params: PathParams): void - /** - * SetPath sets the registered path for the handler. - */ - setPath(p: string): void - /** - * SetRouteInfo sets the route info of this request to the context. - */ - setRouteInfo(ri: RouteInfo): void - /** - * Set saves data in the context. Allows router to store arbitrary (that only router has access to) data in context - * for later use in middlewares/handler. - */ - set(key: string, val: { - }): void - } - /** - * PathParam is tuple pf path parameter name and its value in request path - */ - interface PathParam { - name: string - value: string - } -} - -namespace hook { - /** - * Handler defines a hook handler function. - */ - interface Handler {(e: T): void } - /** - * wrapped local Hook embedded struct to limit the public API surface. - */ - type _subYquQA = Hook - interface mainHook extends _subYquQA { - } -} - -/** - * Package slog provides structured logging, - * in which log records include a message, - * a severity level, and various other attributes - * expressed as key-value pairs. + * then slog will report the source file as mylog.go, not main.go. * - * It defines a type, [Logger], - * which provides several methods (such as [Logger.Info] and [Logger.Error]) - * for reporting events of interest. + * A correct implementation of Infof will obtain the source location + * (pc) and pass it to NewRecord. + * The Infof function in the package-level example called "wrapping" + * demonstrates how to do this. * - * Each Logger is associated with a [Handler]. - * A Logger output method creates a [Record] from the method arguments - * and passes it to the Handler, which decides how to handle it. - * There is a default Logger accessible through top-level functions - * (such as [Info] and [Error]) that call the corresponding Logger methods. + * # Working with Records * - * A log record consists of a time, a level, a message, and a set of key-value - * pairs, where the keys are strings and the values may be of any type. - * As an example, + * Sometimes a Handler will need to modify a Record + * before passing it on to another Handler or backend. + * A Record contains a mixture of simple public fields (e.g. Time, Level, Message) + * and hidden fields that refer to state (such as attributes) indirectly. This + * means that modifying a simple copy of a Record (e.g. by calling + * [Record.Add] or [Record.AddAttrs] to add attributes) + * may have unexpected effects on the original. + * Before modifying a Record, use [Record.Clone] to + * create a copy that shares no state with the original, + * or create a new Record with [NewRecord] + * and build up its Attrs by traversing the old ones with [Record.Attrs]. * - * ``` - * slog.Info("hello", "count", 3) - * ``` + * # Performance considerations * - * creates a record containing the time of the call, - * a level of Info, the message "hello", and a single - * pair with key "count" and value 3. + * If profiling your application demonstrates that logging is taking significant time, + * the following suggestions may help. * - * The [Info] top-level function calls the [Logger.Info] method on the default Logger. - * In addition to [Logger.Info], there are methods for Debug, Warn and Error levels. - * Besides these convenience methods for common levels, - * there is also a [Logger.Log] method which takes the level as an argument. - * Each of these methods has a corresponding top-level function that uses the - * default logger. + * If many log lines have a common attribute, use [Logger.With] to create a Logger with + * that attribute. The built-in handlers will format that attribute only once, at the + * call to [Logger.With]. The [Handler] interface is designed to allow that optimization, + * and a well-written Handler should take advantage of it. * - * The default handler formats the log record's message, time, level, and attributes - * as a string and passes it to the [log] package. + * The arguments to a log call are always evaluated, even if the log event is discarded. + * If possible, defer computation so that it happens only if the value is actually logged. + * For example, consider the call * * ``` - * 2022/11/08 15:28:26 INFO hello count=3 + * slog.Info("starting request", "url", r.URL.String()) // may compute String unnecessarily * ``` * - * For more control over the output format, create a logger with a different handler. - * This statement uses [New] to create a new logger with a [TextHandler] - * that writes structured records in text form to standard error: + * The URL.String method will be called even if the logger discards Info-level events. + * Instead, pass the URL directly: * * ``` - * logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) + * slog.Info("starting request", "url", &r.URL) // calls URL.String only if needed * ``` * - * [TextHandler] output is a sequence of key=value pairs, easily and unambiguously - * parsed by machine. This statement: + * The built-in [TextHandler] will call its String method, but only + * if the log event is enabled. + * Avoiding the call to String also preserves the structure of the underlying value. + * For example [JSONHandler] emits the components of the parsed URL as a JSON object. + * If you want to avoid eagerly paying the cost of the String call + * without causing the handler to potentially inspect the structure of the value, + * wrap the value in a fmt.Stringer implementation that hides its Marshal methods. + * + * You can also use the [LogValuer] interface to avoid unnecessary work in disabled log + * calls. Say you need to log some expensive value: * * ``` - * logger.Info("hello", "count", 3) + * slog.Debug("frobbing", "value", computeExpensiveValue(arg)) * ``` * - * produces this output: + * Even if this line is disabled, computeExpensiveValue will be called. + * To avoid that, define a type implementing LogValuer: * * ``` - * time=2022-11-08T15:28:26.000-05:00 level=INFO msg=hello count=3 + * type expensive struct { arg int } + * + * func (e expensive) LogValue() slog.Value { + * return slog.AnyValue(computeExpensiveValue(e.arg)) + * } * ``` * - * The package also provides [JSONHandler], whose output is line-delimited JSON: + * Then use a value of that type in log calls: * * ``` - * logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) - * logger.Info("hello", "count", 3) + * slog.Debug("frobbing", "value", expensive{arg}) * ``` * - * produces this output: + * Now computeExpensiveValue will only be called when the line is enabled. * - * ``` - * {"time":"2022-11-08T15:28:26.000000000-05:00","level":"INFO","msg":"hello","count":3} - * ``` + * The built-in handlers acquire a lock before calling [io.Writer.Write] + * to ensure that exactly one [Record] is written at a time in its entirety. + * Although each log record has a timestamp, + * the built-in handlers do not use that time to sort the written records. + * User-defined handlers are responsible for their own locking and sorting. * - * Both [TextHandler] and [JSONHandler] can be configured with [HandlerOptions]. - * There are options for setting the minimum level (see Levels, below), - * displaying the source file and line of the log call, and - * modifying attributes before they are logged. + * # Writing a handler * - * Setting a logger as the default with + * For a guide to writing a custom handler, see https://golang.org/s/slog-handler-guide. + */ +namespace slog { + // @ts-ignore + import loginternal = internal + /** + * A Logger records structured information about each call to its + * Log, Debug, Info, Warn, and Error methods. + * For each call, it creates a [Record] and passes it to a [Handler]. + * + * To create a new Logger, call [New] or a Logger method + * that begins "With". + */ + interface Logger { + } + interface Logger { + /** + * Handler returns l's Handler. + */ + handler(): Handler + } + interface Logger { + /** + * With returns a Logger that includes the given attributes + * in each output operation. Arguments are converted to + * attributes as if by [Logger.Log]. + */ + with(...args: any[]): (Logger) + } + interface Logger { + /** + * WithGroup returns a Logger that starts a group, if name is non-empty. + * The keys of all attributes added to the Logger will be qualified by the given + * name. (How that qualification happens depends on the [Handler.WithGroup] + * method of the Logger's Handler.) + * + * If name is empty, WithGroup returns the receiver. + */ + withGroup(name: string): (Logger) + } + interface Logger { + /** + * Enabled reports whether l emits log records at the given context and level. + */ + enabled(ctx: context.Context, level: Level): boolean + } + interface Logger { + /** + * Log emits a log record with the current time and the given level and message. + * The Record's Attrs consist of the Logger's attributes followed by + * the Attrs specified by args. + * + * The attribute arguments are processed as follows: + * ``` + * - If an argument is an Attr, it is used as is. + * - If an argument is a string and this is not the last argument, + * the following argument is treated as the value and the two are combined + * into an Attr. + * - Otherwise, the argument is treated as a value with key "!BADKEY". + * ``` + */ + log(ctx: context.Context, level: Level, msg: string, ...args: any[]): void + } + interface Logger { + /** + * LogAttrs is a more efficient version of [Logger.Log] that accepts only Attrs. + */ + logAttrs(ctx: context.Context, level: Level, msg: string, ...attrs: Attr[]): void + } + interface Logger { + /** + * Debug logs at [LevelDebug]. + */ + debug(msg: string, ...args: any[]): void + } + interface Logger { + /** + * DebugContext logs at [LevelDebug] with the given context. + */ + debugContext(ctx: context.Context, msg: string, ...args: any[]): void + } + interface Logger { + /** + * Info logs at [LevelInfo]. + */ + info(msg: string, ...args: any[]): void + } + interface Logger { + /** + * InfoContext logs at [LevelInfo] with the given context. + */ + infoContext(ctx: context.Context, msg: string, ...args: any[]): void + } + interface Logger { + /** + * Warn logs at [LevelWarn]. + */ + warn(msg: string, ...args: any[]): void + } + interface Logger { + /** + * WarnContext logs at [LevelWarn] with the given context. + */ + warnContext(ctx: context.Context, msg: string, ...args: any[]): void + } + interface Logger { + /** + * Error logs at [LevelError]. + */ + error(msg: string, ...args: any[]): void + } + interface Logger { + /** + * ErrorContext logs at [LevelError] with the given context. + */ + errorContext(ctx: context.Context, msg: string, ...args: any[]): void + } +} + +/** + * Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer + * object, creating another object (Reader or Writer) that also implements + * the interface but provides buffering and some help for textual I/O. + */ +namespace bufio { + /** + * ReadWriter stores pointers to a [Reader] and a [Writer]. + * It implements [io.ReadWriter]. + */ + type _sSzrGWE = Reader&Writer + interface ReadWriter extends _sSzrGWE { + } +} + +namespace hook { + /** + * Event implements [Resolver] and it is intended to be used as a base + * Hook event that you can embed in your custom typed event structs. + * + * Example: + * + * ``` + * type CustomEvent struct { + * hook.Event + * + * SomeField int + * } + * ``` + */ + interface Event { + } + interface Event { + /** + * Next calls the next hook handler. + */ + next(): void + } + /** + * Handler defines a single Hook handler. + * Multiple handlers can share the same id. + * If Id is not explicitly set it will be autogenerated by Hook.Add and Hook.AddHandler. + */ + interface Handler { + /** + * Func defines the handler function to execute. + * + * Note that users need to call e.Next() in order to proceed with + * the execution of the hook chain. + */ + func: (_arg0: T) => void + /** + * Id is the unique identifier of the handler. + * + * It could be used later to remove the handler from a hook via [Hook.Remove]. + * + * If missing, an autogenerated value will be assigned when adding + * the handler to a hook. + */ + id: string + /** + * Priority allows changing the default exec priority of the handler within a hook. + * + * If 0, the handler will be executed in the same order it was registered. + */ + priority: number + } + /** + * Hook defines a generic concurrent safe structure for managing event hooks. + * + * When using custom event it must embed the base [hook.Event]. + * + * Example: + * + * ``` + * type CustomEvent struct { + * hook.Event + * SomeField int + * } + * + * h := Hook[*CustomEvent]{} + * + * h.BindFunc(func(e *CustomEvent) error { + * println(e.SomeField) + * + * return e.Next() + * }) + * + * h.Trigger(&CustomEvent{ SomeField: 123 }) + * ``` + */ + interface Hook { + } + interface Hook { + /** + * Bind registers the provided handler to the current hooks queue. + * + * If handler.Id is empty it is updated with autogenerated value. + * + * If a handler from the current hook list has Id matching handler.Id + * then the old handler is replaced with the new one. + */ + bind(handler: Handler): string + } + interface Hook { + /** + * BindFunc is similar to Bind but registers a new handler from just the provided function. + * + * The registered handler is added with a default 0 priority and the id will be autogenerated. + * + * If you want to register a handler with custom priority or id use the [Hook.Bind] method. + */ + bindFunc(fn: (e: T) => void): string + } + interface Hook { + /** + * Unbind removes one or many hook handler by their id. + */ + unbind(...idsToRemove: string[]): void + } + interface Hook { + /** + * UnbindAll removes all registered handlers. + */ + unbindAll(): void + } + interface Hook { + /** + * Length returns to total number of registered hook handlers. + */ + length(): number + } + interface Hook { + /** + * Trigger executes all registered hook handlers one by one + * with the specified event as an argument. + * + * Optionally, this method allows also to register additional one off + * handler funcs that will be temporary appended to the handlers queue. + * + * NB! Each hook handler must call event.Next() in order the hook chain to proceed. + */ + trigger(event: T, ...oneOffHandlerFuncs: ((_arg0: T) => void)[]): void + } + /** + * TaggedHook defines a proxy hook which register handlers that are triggered only + * if the TaggedHook.tags are empty or includes at least one of the event data tag(s). + */ + type _ssHzwRO = mainHook + interface TaggedHook extends _ssHzwRO { + } + interface TaggedHook { + /** + * CanTriggerOn checks if the current TaggedHook can be triggered with + * the provided event data tags. + * + * It returns always true if the hook doens't have any tags. + */ + canTriggerOn(tagsToCheck: Array): boolean + } + interface TaggedHook { + /** + * Bind registers the provided handler to the current hooks queue. + * + * It is similar to [Hook.Bind] with the difference that the handler + * function is invoked only if the event data tags satisfy h.CanTriggerOn. + */ + bind(handler: Handler): string + } + interface TaggedHook { + /** + * BindFunc registers a new handler with the specified function. + * + * It is similar to [Hook.Bind] with the difference that the handler + * function is invoked only if the event data tags satisfy h.CanTriggerOn. + */ + bindFunc(fn: (e: T) => void): string + } +} + +/** + * Package multipart implements MIME multipart parsing, as defined in RFC + * 2046. * - * ``` - * slog.SetDefault(logger) - * ``` + * The implementation is sufficient for HTTP (RFC 2388) and the multipart + * bodies generated by popular browsers. * - * will cause the top-level functions like [Info] to use it. - * [SetDefault] also updates the default logger used by the [log] package, - * so that existing applications that use [log.Printf] and related functions - * will send log records to the logger's handler without needing to be rewritten. - * - * Some attributes are common to many log calls. - * For example, you may wish to include the URL or trace identifier of a server request - * with all log events arising from the request. - * Rather than repeat the attribute with every log call, you can use [Logger.With] - * to construct a new Logger containing the attributes: - * - * ``` - * logger2 := logger.With("url", r.URL) - * ``` - * - * The arguments to With are the same key-value pairs used in [Logger.Info]. - * The result is a new Logger with the same handler as the original, but additional - * attributes that will appear in the output of every call. - * - * # Levels - * - * A [Level] is an integer representing the importance or severity of a log event. - * The higher the level, the more severe the event. - * This package defines constants for the most common levels, - * but any int can be used as a level. - * - * In an application, you may wish to log messages only at a certain level or greater. - * One common configuration is to log messages at Info or higher levels, - * suppressing debug logging until it is needed. - * The built-in handlers can be configured with the minimum level to output by - * setting [HandlerOptions.Level]. - * The program's `main` function typically does this. - * The default value is LevelInfo. - * - * Setting the [HandlerOptions.Level] field to a [Level] value - * fixes the handler's minimum level throughout its lifetime. - * Setting it to a [LevelVar] allows the level to be varied dynamically. - * A LevelVar holds a Level and is safe to read or write from multiple - * goroutines. - * To vary the level dynamically for an entire program, first initialize - * a global LevelVar: - * - * ``` - * var programLevel = new(slog.LevelVar) // Info by default - * ``` - * - * Then use the LevelVar to construct a handler, and make it the default: - * - * ``` - * h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}) - * slog.SetDefault(slog.New(h)) - * ``` - * - * Now the program can change its logging level with a single statement: - * - * ``` - * programLevel.Set(slog.LevelDebug) - * ``` - * - * # Groups - * - * Attributes can be collected into groups. - * A group has a name that is used to qualify the names of its attributes. - * How this qualification is displayed depends on the handler. - * [TextHandler] separates the group and attribute names with a dot. - * [JSONHandler] treats each group as a separate JSON object, with the group name as the key. - * - * Use [Group] to create a Group attribute from a name and a list of key-value pairs: + * # Limits * - * ``` - * slog.Group("request", - * "method", r.Method, - * "url", r.URL) - * ``` + * To protect against malicious inputs, this package sets limits on the size + * of the MIME data it processes. * - * TextHandler would display this group as + * [Reader.NextPart] and [Reader.NextRawPart] limit the number of headers in a + * part to 10000 and [Reader.ReadForm] limits the total number of headers in all + * FileHeaders to 10000. + * These limits may be adjusted with the GODEBUG=multipartmaxheaders= + * setting. * - * ``` - * request.method=GET request.url=http://example.com - * ``` + * Reader.ReadForm further limits the number of parts in a form to 1000. + * This limit may be adjusted with the GODEBUG=multipartmaxparts= + * setting. + */ +namespace multipart { + /** + * A FileHeader describes a file part of a multipart request. + */ + interface FileHeader { + filename: string + header: textproto.MIMEHeader + size: number + } + interface FileHeader { + /** + * Open opens and returns the [FileHeader]'s associated File. + */ + open(): File + } +} + +/** + * Package http provides HTTP client and server implementations. * - * JSONHandler would display it as + * [Get], [Head], [Post], and [PostForm] make HTTP (or HTTPS) requests: * * ``` - * "request":{"method":"GET","url":"http://example.com"} + * resp, err := http.Get("http://example.com/") + * ... + * resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf) + * ... + * resp, err := http.PostForm("http://example.com/form", + * url.Values{"key": {"Value"}, "id": {"123"}}) * ``` * - * Use [Logger.WithGroup] to qualify all of a Logger's output - * with a group name. Calling WithGroup on a Logger results in a - * new Logger with the same Handler as the original, but with all - * its attributes qualified by the group name. - * - * This can help prevent duplicate attribute keys in large systems, - * where subsystems might use the same keys. - * Pass each subsystem a different Logger with its own group name so that - * potential duplicates are qualified: + * The caller must close the response body when finished with it: * * ``` - * logger := slog.Default().With("id", systemID) - * parserLogger := logger.WithGroup("parser") - * parseInput(input, parserLogger) + * resp, err := http.Get("http://example.com/") + * if err != nil { + * // handle error + * } + * defer resp.Body.Close() + * body, err := io.ReadAll(resp.Body) + * // ... * ``` * - * When parseInput logs with parserLogger, its keys will be qualified with "parser", - * so even if it uses the common key "id", the log line will have distinct keys. - * - * # Contexts - * - * Some handlers may wish to include information from the [context.Context] that is - * available at the call site. One example of such information - * is the identifier for the current span when tracing is enabled. - * - * The [Logger.Log] and [Logger.LogAttrs] methods take a context as a first - * argument, as do their corresponding top-level functions. + * # Clients and Transports * - * Although the convenience methods on Logger (Info and so on) and the - * corresponding top-level functions do not take a context, the alternatives ending - * in "Context" do. For example, + * For control over HTTP client headers, redirect policy, and other + * settings, create a [Client]: * * ``` - * slog.InfoContext(ctx, "message") - * ``` - * - * It is recommended to pass a context to an output method if one is available. - * - * # Attrs and Values + * client := &http.Client{ + * CheckRedirect: redirectPolicyFunc, + * } * - * An [Attr] is a key-value pair. The Logger output methods accept Attrs as well as - * alternating keys and values. The statement + * resp, err := client.Get("http://example.com") + * // ... * - * ``` - * slog.Info("hello", slog.Int("count", 3)) + * req, err := http.NewRequest("GET", "http://example.com", nil) + * // ... + * req.Header.Add("If-None-Match", `W/"wyzzy"`) + * resp, err := client.Do(req) + * // ... * ``` * - * behaves the same as + * For control over proxies, TLS configuration, keep-alives, + * compression, and other settings, create a [Transport]: * * ``` - * slog.Info("hello", "count", 3) + * tr := &http.Transport{ + * MaxIdleConns: 10, + * IdleConnTimeout: 30 * time.Second, + * DisableCompression: true, + * } + * client := &http.Client{Transport: tr} + * resp, err := client.Get("https://example.com") * ``` * - * There are convenience constructors for [Attr] such as [Int], [String], and [Bool] - * for common types, as well as the function [Any] for constructing Attrs of any - * type. - * - * The value part of an Attr is a type called [Value]. - * Like an [any], a Value can hold any Go value, - * but it can represent typical values, including all numbers and strings, - * without an allocation. + * Clients and Transports are safe for concurrent use by multiple + * goroutines and for efficiency should only be created once and re-used. * - * For the most efficient log output, use [Logger.LogAttrs]. - * It is similar to [Logger.Log] but accepts only Attrs, not alternating - * keys and values; this allows it, too, to avoid allocation. + * # Servers * - * The call + * ListenAndServe starts an HTTP server with a given address and handler. + * The handler is usually nil, which means to use [DefaultServeMux]. + * [Handle] and [HandleFunc] add handlers to [DefaultServeMux]: * * ``` - * logger.LogAttrs(ctx, slog.LevelInfo, "hello", slog.Int("count", 3)) - * ``` + * http.Handle("/foo", fooHandler) * - * is the most efficient way to achieve the same output as + * http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) { + * fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) + * }) * + * log.Fatal(http.ListenAndServe(":8080", nil)) * ``` - * slog.InfoContext(ctx, "hello", "count", 3) - * ``` - * - * # Customizing a type's logging behavior - * - * If a type implements the [LogValuer] interface, the [Value] returned from its LogValue - * method is used for logging. You can use this to control how values of the type - * appear in logs. For example, you can redact secret information like passwords, - * or gather a struct's fields in a Group. See the examples under [LogValuer] for - * details. - * - * A LogValue method may return a Value that itself implements [LogValuer]. The [Value.Resolve] - * method handles these cases carefully, avoiding infinite loops and unbounded recursion. - * Handler authors and others may wish to use [Value.Resolve] instead of calling LogValue directly. - * - * # Wrapping output methods * - * The logger functions use reflection over the call stack to find the file name - * and line number of the logging call within the application. This can produce - * incorrect source information for functions that wrap slog. For instance, if you - * define this function in file mylog.go: + * More control over the server's behavior is available by creating a + * custom Server: * * ``` - * func Infof(logger *slog.Logger, format string, args ...any) { - * logger.Info(fmt.Sprintf(format, args...)) + * s := &http.Server{ + * Addr: ":8080", + * Handler: myHandler, + * ReadTimeout: 10 * time.Second, + * WriteTimeout: 10 * time.Second, + * MaxHeaderBytes: 1 << 20, * } + * log.Fatal(s.ListenAndServe()) * ``` * - * and you call it like this in main.go: + * # HTTP/2 + * + * Starting with Go 1.6, the http package has transparent support for the + * HTTP/2 protocol when using HTTPS. Programs that must disable HTTP/2 + * can do so by setting [Transport.TLSNextProto] (for clients) or + * [Server.TLSNextProto] (for servers) to a non-nil, empty + * map. Alternatively, the following GODEBUG settings are + * currently supported: * * ``` - * Infof(slog.Default(), "hello, %s", "world") + * GODEBUG=http2client=0 # disable HTTP/2 client support + * GODEBUG=http2server=0 # disable HTTP/2 server support + * GODEBUG=http2debug=1 # enable verbose HTTP/2 debug logs + * GODEBUG=http2debug=2 # ... even more verbose, with frame dumps * ``` * - * then slog will report the source file as mylog.go, not main.go. + * Please report any issues before disabling HTTP/2 support: https://golang.org/s/http2bug * - * A correct implementation of Infof will obtain the source location - * (pc) and pass it to NewRecord. - * The Infof function in the package-level example called "wrapping" - * demonstrates how to do this. - * - * # Working with Records - * - * Sometimes a Handler will need to modify a Record - * before passing it on to another Handler or backend. - * A Record contains a mixture of simple public fields (e.g. Time, Level, Message) - * and hidden fields that refer to state (such as attributes) indirectly. This - * means that modifying a simple copy of a Record (e.g. by calling - * [Record.Add] or [Record.AddAttrs] to add attributes) - * may have unexpected effects on the original. - * Before modifying a Record, use [Record.Clone] to - * create a copy that shares no state with the original, - * or create a new Record with [NewRecord] - * and build up its Attrs by traversing the old ones with [Record.Attrs]. - * - * # Performance considerations - * - * If profiling your application demonstrates that logging is taking significant time, - * the following suggestions may help. - * - * If many log lines have a common attribute, use [Logger.With] to create a Logger with - * that attribute. The built-in handlers will format that attribute only once, at the - * call to [Logger.With]. The [Handler] interface is designed to allow that optimization, - * and a well-written Handler should take advantage of it. - * - * The arguments to a log call are always evaluated, even if the log event is discarded. - * If possible, defer computation so that it happens only if the value is actually logged. - * For example, consider the call - * - * ``` - * slog.Info("starting request", "url", r.URL.String()) // may compute String unnecessarily - * ``` - * - * The URL.String method will be called even if the logger discards Info-level events. - * Instead, pass the URL directly: - * - * ``` - * slog.Info("starting request", "url", &r.URL) // calls URL.String only if needed - * ``` - * - * The built-in [TextHandler] will call its String method, but only - * if the log event is enabled. - * Avoiding the call to String also preserves the structure of the underlying value. - * For example [JSONHandler] emits the components of the parsed URL as a JSON object. - * If you want to avoid eagerly paying the cost of the String call - * without causing the handler to potentially inspect the structure of the value, - * wrap the value in a fmt.Stringer implementation that hides its Marshal methods. - * - * You can also use the [LogValuer] interface to avoid unnecessary work in disabled log - * calls. Say you need to log some expensive value: - * - * ``` - * slog.Debug("frobbing", "value", computeExpensiveValue(arg)) - * ``` - * - * Even if this line is disabled, computeExpensiveValue will be called. - * To avoid that, define a type implementing LogValuer: - * - * ``` - * type expensive struct { arg int } - * - * func (e expensive) LogValue() slog.Value { - * return slog.AnyValue(computeExpensiveValue(e.arg)) - * } - * ``` - * - * Then use a value of that type in log calls: - * - * ``` - * slog.Debug("frobbing", "value", expensive{arg}) - * ``` - * - * Now computeExpensiveValue will only be called when the line is enabled. - * - * The built-in handlers acquire a lock before calling [io.Writer.Write] - * to ensure that exactly one [Record] is written at a time in its entirety. - * Although each log record has a timestamp, - * the built-in handlers do not use that time to sort the written records. - * User-defined handlers are responsible for their own locking and sorting. - * - * # Writing a handler - * - * For a guide to writing a custom handler, see https://golang.org/s/slog-handler-guide. + * The http package's [Transport] and [Server] both automatically enable + * HTTP/2 support for simple configurations. To enable HTTP/2 for more + * complex configurations, to use lower-level HTTP/2 features, or to use + * a newer version of Go's http2 package, import "golang.org/x/net/http2" + * directly and use its ConfigureTransport and/or ConfigureServer + * functions. Manually configuring HTTP/2 via the golang.org/x/net/http2 + * package takes precedence over the net/http package's built-in HTTP/2 + * support. */ -namespace slog { +namespace http { + // @ts-ignore + import mathrand = rand /** - * An Attr is a key-value pair. + * PushOptions describes options for [Pusher.Push]. */ - interface Attr { - key: string - value: Value - } - interface Attr { + interface PushOptions { /** - * Equal reports whether a and b have equal keys and values. + * Method specifies the HTTP method for the promised request. + * If set, it must be "GET" or "HEAD". Empty means "GET". */ - equal(b: Attr): boolean - } - interface Attr { - string(): string + method: string + /** + * Header specifies additional promised request headers. This cannot + * include HTTP/2 pseudo header fields like ":path" and ":scheme", + * which will be added automatically. + */ + header: Header } + // @ts-ignore + import urlpkg = url /** - * A Handler handles log records produced by a Logger. - * - * A typical handler may print log records to standard error, - * or write them to a file or database, or perhaps augment them - * with additional attributes and pass them on to another handler. - * - * Any of the Handler's methods may be called concurrently with itself - * or with other methods. It is the responsibility of the Handler to - * manage this concurrency. + * A Request represents an HTTP request received by a server + * or to be sent by a client. * - * Users of the slog package should not invoke Handler methods directly. - * They should use the methods of [Logger] instead. + * The field semantics differ slightly between client and server + * usage. In addition to the notes on the fields below, see the + * documentation for [Request.Write] and [RoundTripper]. */ - interface Handler { - [key:string]: any; + interface Request { /** - * Enabled reports whether the handler handles records at the given level. - * The handler ignores records whose level is lower. - * It is called early, before any arguments are processed, - * to save effort if the log event should be discarded. - * If called from a Logger method, the first argument is the context - * passed to that method, or context.Background() if nil was passed - * or the method does not take a context. - * The context is passed so Enabled can use its values - * to make a decision. + * Method specifies the HTTP method (GET, POST, PUT, etc.). + * For client requests, an empty string means GET. */ - enabled(_arg0: context.Context, _arg1: Level): boolean + method: string /** - * Handle handles the Record. - * It will only be called when Enabled returns true. - * The Context argument is as for Enabled. - * It is present solely to provide Handlers access to the context's values. - * Canceling the context should not affect record processing. - * (Among other things, log messages may be necessary to debug a - * cancellation-related problem.) + * URL specifies either the URI being requested (for server + * requests) or the URL to access (for client requests). * - * Handle methods that produce output should observe the following rules: - * ``` - * - If r.Time is the zero time, ignore the time. - * - If r.PC is zero, ignore it. - * - Attr's values should be resolved. - * - If an Attr's key and value are both the zero value, ignore the Attr. - * This can be tested with attr.Equal(Attr{}). - * - If a group's key is empty, inline the group's Attrs. - * - If a group has no Attrs (even if it has a non-empty key), - * ignore it. - * ``` + * For server requests, the URL is parsed from the URI + * supplied on the Request-Line as stored in RequestURI. For + * most requests, fields other than Path and RawQuery will be + * empty. (See RFC 7230, Section 5.3) + * + * For client requests, the URL's Host specifies the server to + * connect to, while the Request's Host field optionally + * specifies the Host header value to send in the HTTP + * request. */ - handle(_arg0: context.Context, _arg1: Record): void + url?: url.URL /** - * WithAttrs returns a new Handler whose attributes consist of - * both the receiver's attributes and the arguments. - * The Handler owns the slice: it may retain, modify or discard it. + * The protocol version for incoming server requests. + * + * For client requests, these fields are ignored. The HTTP + * client code always uses either HTTP/1.1 or HTTP/2. + * See the docs on Transport for details. */ - withAttrs(attrs: Array): Handler + proto: string // "HTTP/1.0" + protoMajor: number // 1 + protoMinor: number // 0 /** - * WithGroup returns a new Handler with the given group appended to - * the receiver's existing groups. - * The keys of all subsequent attributes, whether added by With or in a - * Record, should be qualified by the sequence of group names. - * - * How this qualification happens is up to the Handler, so long as - * this Handler's attribute keys differ from those of another Handler - * with a different sequence of group names. + * Header contains the request header fields either received + * by the server or to be sent by the client. * - * A Handler should treat WithGroup as starting a Group of Attrs that ends - * at the end of the log event. That is, + * If a server received a request with header lines, * * ``` - * logger.WithGroup("s").LogAttrs(ctx, level, msg, slog.Int("a", 1), slog.Int("b", 2)) + * Host: example.com + * accept-encoding: gzip, deflate + * Accept-Language: en-us + * fOO: Bar + * foo: two * ``` * - * should behave like + * then * * ``` - * logger.LogAttrs(ctx, level, msg, slog.Group("s", slog.Int("a", 1), slog.Int("b", 2))) + * Header = map[string][]string{ + * "Accept-Encoding": {"gzip, deflate"}, + * "Accept-Language": {"en-us"}, + * "Foo": {"Bar", "two"}, + * } * ``` * - * If the name is empty, WithGroup returns the receiver. - */ - withGroup(name: string): Handler - } - /** - * A Level is the importance or severity of a log event. - * The higher the level, the more important or severe the event. - */ - interface Level extends Number{} - interface Level { - /** - * String returns a name for the level. - * If the level has a name, then that name - * in uppercase is returned. - * If the level is between named values, then - * an integer is appended to the uppercased name. - * Examples: + * For incoming requests, the Host header is promoted to the + * Request.Host field and removed from the Header map. * - * ``` - * LevelWarn.String() => "WARN" - * (LevelInfo+2).String() => "INFO+2" - * ``` + * HTTP defines that header names are case-insensitive. The + * request parser implements this by using CanonicalHeaderKey, + * making the first character and any characters following a + * hyphen uppercase and the rest lowercase. + * + * For client requests, certain headers such as Content-Length + * and Connection are automatically written when needed and + * values in Header may be ignored. See the documentation + * for the Request.Write method. */ - string(): string - } - interface Level { + header: Header /** - * MarshalJSON implements [encoding/json.Marshaler] - * by quoting the output of [Level.String]. - */ - marshalJSON(): string|Array - } - interface Level { - /** - * UnmarshalJSON implements [encoding/json.Unmarshaler] - * It accepts any string produced by [Level.MarshalJSON], - * ignoring case. - * It also accepts numeric offsets that would result in a different string on - * output. For example, "Error-8" would marshal as "INFO". + * Body is the request's body. + * + * For client requests, a nil body means the request has no + * body, such as a GET request. The HTTP Client's Transport + * is responsible for calling the Close method. + * + * For server requests, the Request Body is always non-nil + * but will return EOF immediately when no body is present. + * The Server will close the request body. The ServeHTTP + * Handler does not need to. + * + * Body must allow Read to be called concurrently with Close. + * In particular, calling Close should unblock a Read waiting + * for input. */ - unmarshalJSON(data: string|Array): void - } - interface Level { + body: io.ReadCloser /** - * MarshalText implements [encoding.TextMarshaler] - * by calling [Level.String]. + * GetBody defines an optional func to return a new copy of + * Body. It is used for client requests when a redirect requires + * reading the body more than once. Use of GetBody still + * requires setting Body. + * + * For server requests, it is unused. */ - marshalText(): string|Array - } - interface Level { + getBody: () => io.ReadCloser /** - * UnmarshalText implements [encoding.TextUnmarshaler]. - * It accepts any string produced by [Level.MarshalText], - * ignoring case. - * It also accepts numeric offsets that would result in a different string on - * output. For example, "Error-8" would marshal as "INFO". + * ContentLength records the length of the associated content. + * The value -1 indicates that the length is unknown. + * Values >= 0 indicate that the given number of bytes may + * be read from Body. + * + * For client requests, a value of 0 with a non-nil Body is + * also treated as unknown. */ - unmarshalText(data: string|Array): void - } - interface Level { + contentLength: number /** - * Level returns the receiver. - * It implements [Leveler]. + * TransferEncoding lists the transfer encodings from outermost to + * innermost. An empty list denotes the "identity" encoding. + * TransferEncoding can usually be ignored; chunked encoding is + * automatically added and removed as necessary when sending and + * receiving requests. */ - level(): Level - } - // @ts-ignore - import loginternal = internal -} - -namespace settings { - // @ts-ignore - import validation = ozzo_validation - interface EmailTemplate { - body: string - subject: string - actionUrl: string - hidden: boolean - } - interface EmailTemplate { + transferEncoding: Array /** - * Validate makes EmailTemplate validatable by implementing [validation.Validatable] interface. + * Close indicates whether to close the connection after + * replying to this request (for servers) or after sending this + * request and reading its response (for clients). + * + * For server requests, the HTTP server handles this automatically + * and this field is not needed by Handlers. + * + * For client requests, setting this field prevents re-use of + * TCP connections between requests to the same hosts, as if + * Transport.DisableKeepAlives were set. */ - validate(): void - } - interface EmailTemplate { + close: boolean /** - * Resolve replaces the placeholder parameters in the current email - * template and returns its components as ready-to-use strings. + * For server requests, Host specifies the host on which the + * URL is sought. For HTTP/1 (per RFC 7230, section 5.4), this + * is either the value of the "Host" header or the host name + * given in the URL itself. For HTTP/2, it is the value of the + * ":authority" pseudo-header field. + * It may be of the form "host:port". For international domain + * names, Host may be in Punycode or Unicode form. Use + * golang.org/x/net/idna to convert it to either format if + * needed. + * To prevent DNS rebinding attacks, server Handlers should + * validate that the Host header has a value for which the + * Handler considers itself authoritative. The included + * ServeMux supports patterns registered to particular host + * names and thus protects its registered Handlers. + * + * For client requests, Host optionally overrides the Host + * header to send. If empty, the Request.Write method uses + * the value of URL.Host. Host may contain an international + * domain name. */ - resolve(appName: string, appUrl: string, token: string): [string, string, string] - } -} - -namespace subscriptions { - /** - * Message defines a client's channel data. - */ - interface Message { - name: string - data: string|Array - } - /** - * Client is an interface for a generic subscription client. - */ - interface Client { - [key:string]: any; + host: string /** - * Id Returns the unique id of the client. + * Form contains the parsed form data, including both the URL + * field's query parameters and the PATCH, POST, or PUT form data. + * This field is only available after ParseForm is called. + * The HTTP client ignores Form and uses Body instead. */ - id(): string + form: url.Values /** - * Channel returns the client's communication channel. + * PostForm contains the parsed form data from PATCH, POST + * or PUT body parameters. + * + * This field is only available after ParseForm is called. + * The HTTP client ignores PostForm and uses Body instead. */ - channel(): undefined + postForm: url.Values /** - * Subscriptions returns a shallow copy of the client subscriptions matching the prefixes. - * If no prefix is specified, returns all subscriptions. + * MultipartForm is the parsed multipart form, including file uploads. + * This field is only available after ParseMultipartForm is called. + * The HTTP client ignores MultipartForm and uses Body instead. */ - subscriptions(...prefixes: string[]): _TygojaDict + multipartForm?: multipart.Form /** - * Subscribe subscribes the client to the provided subscriptions list. + * Trailer specifies additional headers that are sent after the request + * body. * - * Each subscription can also have "options" (json serialized SubscriptionOptions) as query parameter. + * For server requests, the Trailer map initially contains only the + * trailer keys, with nil values. (The client declares which trailers it + * will later send.) While the handler is reading from Body, it must + * not reference Trailer. After reading from Body returns EOF, Trailer + * can be read again and will contain non-nil values, if they were sent + * by the client. * - * Example: + * For client requests, Trailer must be initialized to a map containing + * the trailer keys to later send. The values may be nil or their final + * values. The ContentLength must be 0 or -1, to send a chunked request. + * After the HTTP request is sent the map values can be updated while + * the request body is read. Once the body returns EOF, the caller must + * not mutate Trailer. * - * ``` - * Subscribe( - * "subscriptionA", - * `subscriptionB?options={"query":{"a":1},"headers":{"x_token":"abc"}}`, - * ) - * ``` - */ - subscribe(...subs: string[]): void - /** - * Unsubscribe unsubscribes the client from the provided subscriptions list. + * Few HTTP clients, servers, or proxies support HTTP trailers. */ - unsubscribe(...subs: string[]): void + trailer: Header /** - * HasSubscription checks if the client is subscribed to `sub`. + * RemoteAddr allows HTTP servers and other software to record + * the network address that sent the request, usually for + * logging. This field is not filled in by ReadRequest and + * has no defined format. The HTTP server in this package + * sets RemoteAddr to an "IP:port" address before invoking a + * handler. + * This field is ignored by the HTTP client. */ - hasSubscription(sub: string): boolean + remoteAddr: string /** - * Set stores any value to the client's context. + * RequestURI is the unmodified request-target of the + * Request-Line (RFC 7230, Section 3.1.1) as sent by the client + * to a server. Usually the URL field should be used instead. + * It is an error to set this field in an HTTP client request. */ - set(key: string, value: any): void + requestURI: string /** - * Unset removes a single value from the client's context. + * TLS allows HTTP servers and other software to record + * information about the TLS connection on which the request + * was received. This field is not filled in by ReadRequest. + * The HTTP server in this package sets the field for + * TLS-enabled connections before invoking a handler; + * otherwise it leaves the field nil. + * This field is ignored by the HTTP client. */ - unset(key: string): void + tls?: any /** - * Get retrieves the key value from the client's context. + * Cancel is an optional channel whose closure indicates that the client + * request should be regarded as canceled. Not all implementations of + * RoundTripper may support Cancel. + * + * For server requests, this field is not applicable. + * + * Deprecated: Set the Request's context with NewRequestWithContext + * instead. If a Request's Cancel field and context are both + * set, it is undefined whether Cancel is respected. */ - get(key: string): any + cancel: undefined /** - * Discard marks the client as "discarded", meaning that it - * shouldn't be used anymore for sending new messages. - * - * It is safe to call Discard() multiple times. + * Response is the redirect response which caused this request + * to be created. This field is only populated during client + * redirects. */ - discard(): void + response?: Response /** - * IsDiscarded indicates whether the client has been "discarded" - * and should no longer be used. + * Pattern is the [ServeMux] pattern that matched the request. + * It is empty if the request was not matched against a pattern. */ - isDiscarded(): boolean + pattern: string + } + interface Request { /** - * Send sends the specified message to the client's channel (if not discarded). + * Context returns the request's context. To change the context, use + * [Request.Clone] or [Request.WithContext]. + * + * The returned context is always non-nil; it defaults to the + * background context. + * + * For outgoing client requests, the context controls cancellation. + * + * For incoming server requests, the context is canceled when the + * client's connection closes, the request is canceled (with HTTP/2), + * or when the ServeHTTP method returns. */ - send(m: Message): void + context(): context.Context } -} - -/** - * Package core is the backbone of PocketBase. - * - * It defines the main PocketBase App interface and its base implementation. - */ -namespace core { - interface BaseModelEvent { - model: models.Model - } - interface BaseModelEvent { - tags(): Array - } - interface BaseCollectionEvent { - collection?: models.Collection - } - interface BaseCollectionEvent { - tags(): Array - } -} - -/** - * Package types implements some commonly used db serializable types - * like datetime, json, etc. - */ -namespace types { -} - -/** - * Package bufio implements buffered I/O. It wraps an io.Reader or io.Writer - * object, creating another object (Reader or Writer) that also implements - * the interface but provides buffering and some help for textual I/O. - */ -namespace bufio { - /** - * Reader implements buffering for an io.Reader object. - */ - interface Reader { - } - interface Reader { - /** - * Size returns the size of the underlying buffer in bytes. - */ - size(): number - } - interface Reader { + interface Request { /** - * Reset discards any buffered data, resets all state, and switches - * the buffered reader to read from r. - * Calling Reset on the zero value of [Reader] initializes the internal buffer - * to the default size. - * Calling b.Reset(b) (that is, resetting a [Reader] to itself) does nothing. + * WithContext returns a shallow copy of r with its context changed + * to ctx. The provided ctx must be non-nil. + * + * For outgoing client request, the context controls the entire + * lifetime of a request and its response: obtaining a connection, + * sending the request, and reading the response headers and body. + * + * To create a new request with a context, use [NewRequestWithContext]. + * To make a deep copy of a request with a new context, use [Request.Clone]. */ - reset(r: io.Reader): void + withContext(ctx: context.Context): (Request) } - interface Reader { + interface Request { /** - * Peek returns the next n bytes without advancing the reader. The bytes stop - * being valid at the next read call. If Peek returns fewer than n bytes, it - * also returns an error explaining why the read is short. The error is - * [ErrBufferFull] if n is larger than b's buffer size. + * Clone returns a deep copy of r with its context changed to ctx. + * The provided ctx must be non-nil. * - * Calling Peek prevents a [Reader.UnreadByte] or [Reader.UnreadRune] call from succeeding - * until the next read operation. + * Clone only makes a shallow copy of the Body field. + * + * For an outgoing client request, the context controls the entire + * lifetime of a request and its response: obtaining a connection, + * sending the request, and reading the response headers and body. */ - peek(n: number): string|Array + clone(ctx: context.Context): (Request) } - interface Reader { + interface Request { /** - * Discard skips the next n bytes, returning the number of bytes discarded. - * - * If Discard skips fewer than n bytes, it also returns an error. - * If 0 <= n <= b.Buffered(), Discard is guaranteed to succeed without - * reading from the underlying io.Reader. + * ProtoAtLeast reports whether the HTTP protocol used + * in the request is at least major.minor. */ - discard(n: number): number + protoAtLeast(major: number, minor: number): boolean } - interface Reader { + interface Request { /** - * Read reads data into p. - * It returns the number of bytes read into p. - * The bytes are taken from at most one Read on the underlying [Reader], - * hence n may be less than len(p). - * To read exactly len(p) bytes, use io.ReadFull(b, p). - * If the underlying [Reader] can return a non-zero count with io.EOF, - * then this Read method can do so as well; see the [io.Reader] docs. + * UserAgent returns the client's User-Agent, if sent in the request. */ - read(p: string|Array): number + userAgent(): string } - interface Reader { + interface Request { /** - * ReadByte reads and returns a single byte. - * If no byte is available, returns an error. + * Cookies parses and returns the HTTP cookies sent with the request. */ - readByte(): number + cookies(): Array<(Cookie | undefined)> } - interface Reader { + interface Request { /** - * UnreadByte unreads the last byte. Only the most recently read byte can be unread. - * - * UnreadByte returns an error if the most recent method called on the - * [Reader] was not a read operation. Notably, [Reader.Peek], [Reader.Discard], and [Reader.WriteTo] are not - * considered read operations. + * CookiesNamed parses and returns the named HTTP cookies sent with the request + * or an empty slice if none matched. */ - unreadByte(): void + cookiesNamed(name: string): Array<(Cookie | undefined)> } - interface Reader { + interface Request { /** - * ReadRune reads a single UTF-8 encoded Unicode character and returns the - * rune and its size in bytes. If the encoded rune is invalid, it consumes one byte - * and returns unicode.ReplacementChar (U+FFFD) with a size of 1. + * Cookie returns the named cookie provided in the request or + * [ErrNoCookie] if not found. + * If multiple cookies match the given name, only one cookie will + * be returned. */ - readRune(): [number, number] + cookie(name: string): (Cookie) } - interface Reader { + interface Request { /** - * UnreadRune unreads the last rune. If the most recent method called on - * the [Reader] was not a [Reader.ReadRune], [Reader.UnreadRune] returns an error. (In this - * regard it is stricter than [Reader.UnreadByte], which will unread the last byte - * from any read operation.) + * AddCookie adds a cookie to the request. Per RFC 6265 section 5.4, + * AddCookie does not attach more than one [Cookie] header field. That + * means all cookies, if any, are written into the same line, + * separated by semicolon. + * AddCookie only sanitizes c's name and value, and does not sanitize + * a Cookie header already present in the request. */ - unreadRune(): void + addCookie(c: Cookie): void } - interface Reader { + interface Request { /** - * Buffered returns the number of bytes that can be read from the current buffer. + * Referer returns the referring URL, if sent in the request. + * + * Referer is misspelled as in the request itself, a mistake from the + * earliest days of HTTP. This value can also be fetched from the + * [Header] map as Header["Referer"]; the benefit of making it available + * as a method is that the compiler can diagnose programs that use the + * alternate (correct English) spelling req.Referrer() but cannot + * diagnose programs that use Header["Referrer"]. */ - buffered(): number + referer(): string } - interface Reader { + interface Request { /** - * ReadSlice reads until the first occurrence of delim in the input, - * returning a slice pointing at the bytes in the buffer. - * The bytes stop being valid at the next read. - * If ReadSlice encounters an error before finding a delimiter, - * it returns all the data in the buffer and the error itself (often io.EOF). - * ReadSlice fails with error [ErrBufferFull] if the buffer fills without a delim. - * Because the data returned from ReadSlice will be overwritten - * by the next I/O operation, most clients should use - * [Reader.ReadBytes] or ReadString instead. - * ReadSlice returns err != nil if and only if line does not end in delim. + * MultipartReader returns a MIME multipart reader if this is a + * multipart/form-data or a multipart/mixed POST request, else returns nil and an error. + * Use this function instead of [Request.ParseMultipartForm] to + * process the request body as a stream. */ - readSlice(delim: number): string|Array + multipartReader(): (multipart.Reader) } - interface Reader { + interface Request { /** - * ReadLine is a low-level line-reading primitive. Most callers should use - * [Reader.ReadBytes]('\n') or [Reader.ReadString]('\n') instead or use a [Scanner]. + * Write writes an HTTP/1.1 request, which is the header and body, in wire format. + * This method consults the following fields of the request: * - * ReadLine tries to return a single line, not including the end-of-line bytes. - * If the line was too long for the buffer then isPrefix is set and the - * beginning of the line is returned. The rest of the line will be returned - * from future calls. isPrefix will be false when returning the last fragment - * of the line. The returned buffer is only valid until the next call to - * ReadLine. ReadLine either returns a non-nil line or it returns an error, - * never both. + * ``` + * Host + * URL + * Method (defaults to "GET") + * Header + * ContentLength + * TransferEncoding + * Body + * ``` * - * The text returned from ReadLine does not include the line end ("\r\n" or "\n"). - * No indication or error is given if the input ends without a final line end. - * Calling [Reader.UnreadByte] after ReadLine will always unread the last byte read - * (possibly a character belonging to the line end) even if that byte is not - * part of the line returned by ReadLine. + * If Body is present, Content-Length is <= 0 and [Request.TransferEncoding] + * hasn't been set to "identity", Write adds "Transfer-Encoding: + * chunked" to the header. Body is closed after it is sent. */ - readLine(): [string|Array, boolean] + write(w: io.Writer): void } - interface Reader { + interface Request { /** - * ReadBytes reads until the first occurrence of delim in the input, - * returning a slice containing the data up to and including the delimiter. - * If ReadBytes encounters an error before finding a delimiter, - * it returns the data read before the error and the error itself (often io.EOF). - * ReadBytes returns err != nil if and only if the returned data does not end in - * delim. - * For simple uses, a Scanner may be more convenient. + * WriteProxy is like [Request.Write] but writes the request in the form + * expected by an HTTP proxy. In particular, [Request.WriteProxy] writes the + * initial Request-URI line of the request with an absolute URI, per + * section 5.3 of RFC 7230, including the scheme and host. + * In either case, WriteProxy also writes a Host header, using + * either r.Host or r.URL.Host. */ - readBytes(delim: number): string|Array + writeProxy(w: io.Writer): void } - interface Reader { + interface Request { /** - * ReadString reads until the first occurrence of delim in the input, - * returning a string containing the data up to and including the delimiter. - * If ReadString encounters an error before finding a delimiter, - * it returns the data read before the error and the error itself (often io.EOF). - * ReadString returns err != nil if and only if the returned data does not end in - * delim. - * For simple uses, a Scanner may be more convenient. + * BasicAuth returns the username and password provided in the request's + * Authorization header, if the request uses HTTP Basic Authentication. + * See RFC 2617, Section 2. */ - readString(delim: number): string + basicAuth(): [string, string, boolean] } - interface Reader { + interface Request { /** - * WriteTo implements io.WriterTo. - * This may make multiple calls to the [Reader.Read] method of the underlying [Reader]. - * If the underlying reader supports the [Reader.WriteTo] method, - * this calls the underlying [Reader.WriteTo] without buffering. + * SetBasicAuth sets the request's Authorization header to use HTTP + * Basic Authentication with the provided username and password. + * + * With HTTP Basic Authentication the provided username and password + * are not encrypted. It should generally only be used in an HTTPS + * request. + * + * The username may not contain a colon. Some protocols may impose + * additional requirements on pre-escaping the username and + * password. For instance, when used with OAuth2, both arguments must + * be URL encoded first with [url.QueryEscape]. */ - writeTo(w: io.Writer): number - } - /** - * Writer implements buffering for an [io.Writer] object. - * If an error occurs writing to a [Writer], no more data will be - * accepted and all subsequent writes, and [Writer.Flush], will return the error. - * After all data has been written, the client should call the - * [Writer.Flush] method to guarantee all data has been forwarded to - * the underlying [io.Writer]. - */ - interface Writer { + setBasicAuth(username: string, password: string): void } - interface Writer { + interface Request { /** - * Size returns the size of the underlying buffer in bytes. + * ParseForm populates r.Form and r.PostForm. + * + * For all requests, ParseForm parses the raw query from the URL and updates + * r.Form. + * + * For POST, PUT, and PATCH requests, it also reads the request body, parses it + * as a form and puts the results into both r.PostForm and r.Form. Request body + * parameters take precedence over URL query string values in r.Form. + * + * If the request Body's size has not already been limited by [MaxBytesReader], + * the size is capped at 10MB. + * + * For other HTTP methods, or when the Content-Type is not + * application/x-www-form-urlencoded, the request Body is not read, and + * r.PostForm is initialized to a non-nil, empty value. + * + * [Request.ParseMultipartForm] calls ParseForm automatically. + * ParseForm is idempotent. */ - size(): number + parseForm(): void } - interface Writer { + interface Request { /** - * Reset discards any unflushed buffered data, clears any error, and - * resets b to write its output to w. - * Calling Reset on the zero value of [Writer] initializes the internal buffer - * to the default size. - * Calling w.Reset(w) (that is, resetting a [Writer] to itself) does nothing. + * ParseMultipartForm parses a request body as multipart/form-data. + * The whole request body is parsed and up to a total of maxMemory bytes of + * its file parts are stored in memory, with the remainder stored on + * disk in temporary files. + * ParseMultipartForm calls [Request.ParseForm] if necessary. + * If ParseForm returns an error, ParseMultipartForm returns it but also + * continues parsing the request body. + * After one call to ParseMultipartForm, subsequent calls have no effect. */ - reset(w: io.Writer): void + parseMultipartForm(maxMemory: number): void } - interface Writer { + interface Request { /** - * Flush writes any buffered data to the underlying [io.Writer]. + * FormValue returns the first value for the named component of the query. + * The precedence order: + * 1. application/x-www-form-urlencoded form body (POST, PUT, PATCH only) + * 2. query parameters (always) + * 3. multipart/form-data form body (always) + * + * FormValue calls [Request.ParseMultipartForm] and [Request.ParseForm] + * if necessary and ignores any errors returned by these functions. + * If key is not present, FormValue returns the empty string. + * To access multiple values of the same key, call ParseForm and + * then inspect [Request.Form] directly. */ - flush(): void + formValue(key: string): string } - interface Writer { + interface Request { /** - * Available returns how many bytes are unused in the buffer. + * PostFormValue returns the first value for the named component of the POST, + * PUT, or PATCH request body. URL query parameters are ignored. + * PostFormValue calls [Request.ParseMultipartForm] and [Request.ParseForm] if necessary and ignores + * any errors returned by these functions. + * If key is not present, PostFormValue returns the empty string. */ - available(): number + postFormValue(key: string): string } - interface Writer { + interface Request { /** - * AvailableBuffer returns an empty buffer with b.Available() capacity. - * This buffer is intended to be appended to and - * passed to an immediately succeeding [Writer.Write] call. - * The buffer is only valid until the next write operation on b. + * FormFile returns the first file for the provided form key. + * FormFile calls [Request.ParseMultipartForm] and [Request.ParseForm] if necessary. */ - availableBuffer(): string|Array + formFile(key: string): [multipart.File, (multipart.FileHeader)] } - interface Writer { + interface Request { /** - * Buffered returns the number of bytes that have been written into the current buffer. + * PathValue returns the value for the named path wildcard in the [ServeMux] pattern + * that matched the request. + * It returns the empty string if the request was not matched against a pattern + * or there is no such wildcard in the pattern. */ - buffered(): number + pathValue(name: string): string } - interface Writer { + interface Request { /** - * Write writes the contents of p into the buffer. - * It returns the number of bytes written. - * If nn < len(p), it also returns an error explaining - * why the write is short. + * SetPathValue sets name to value, so that subsequent calls to r.PathValue(name) + * return value. */ - write(p: string|Array): number + setPathValue(name: string, value: string): void } - interface Writer { - /** - * WriteByte writes a single byte. - */ - writeByte(c: number): void + /** + * A Handler responds to an HTTP request. + * + * [Handler.ServeHTTP] should write reply headers and data to the [ResponseWriter] + * and then return. Returning signals that the request is finished; it + * is not valid to use the [ResponseWriter] or read from the + * [Request.Body] after or concurrently with the completion of the + * ServeHTTP call. + * + * Depending on the HTTP client software, HTTP protocol version, and + * any intermediaries between the client and the Go server, it may not + * be possible to read from the [Request.Body] after writing to the + * [ResponseWriter]. Cautious handlers should read the [Request.Body] + * first, and then reply. + * + * Except for reading the body, handlers should not modify the + * provided Request. + * + * If ServeHTTP panics, the server (the caller of ServeHTTP) assumes + * that the effect of the panic was isolated to the active request. + * It recovers the panic, logs a stack trace to the server error log, + * and either closes the network connection or sends an HTTP/2 + * RST_STREAM, depending on the HTTP protocol. To abort a handler so + * the client sees an interrupted response but the server doesn't log + * an error, panic with the value [ErrAbortHandler]. + */ + interface Handler { + [key:string]: any; + serveHTTP(_arg0: ResponseWriter, _arg1: Request): void } - interface Writer { + /** + * A ResponseWriter interface is used by an HTTP handler to + * construct an HTTP response. + * + * A ResponseWriter may not be used after [Handler.ServeHTTP] has returned. + */ + interface ResponseWriter { + [key:string]: any; /** - * WriteRune writes a single Unicode code point, returning - * the number of bytes written and any error. + * Header returns the header map that will be sent by + * [ResponseWriter.WriteHeader]. The [Header] map also is the mechanism with which + * [Handler] implementations can set HTTP trailers. + * + * Changing the header map after a call to [ResponseWriter.WriteHeader] (or + * [ResponseWriter.Write]) has no effect unless the HTTP status code was of the + * 1xx class or the modified headers are trailers. + * + * There are two ways to set Trailers. The preferred way is to + * predeclare in the headers which trailers you will later + * send by setting the "Trailer" header to the names of the + * trailer keys which will come later. In this case, those + * keys of the Header map are treated as if they were + * trailers. See the example. The second way, for trailer + * keys not known to the [Handler] until after the first [ResponseWriter.Write], + * is to prefix the [Header] map keys with the [TrailerPrefix] + * constant value. + * + * To suppress automatic response headers (such as "Date"), set + * their value to nil. */ - writeRune(r: number): number - } - interface Writer { + header(): Header /** - * WriteString writes a string. - * It returns the number of bytes written. - * If the count is less than len(s), it also returns an error explaining - * why the write is short. + * Write writes the data to the connection as part of an HTTP reply. + * + * If [ResponseWriter.WriteHeader] has not yet been called, Write calls + * WriteHeader(http.StatusOK) before writing the data. If the Header + * does not contain a Content-Type line, Write adds a Content-Type set + * to the result of passing the initial 512 bytes of written data to + * [DetectContentType]. Additionally, if the total size of all written + * data is under a few KB and there are no Flush calls, the + * Content-Length header is added automatically. + * + * Depending on the HTTP protocol version and the client, calling + * Write or WriteHeader may prevent future reads on the + * Request.Body. For HTTP/1.x requests, handlers should read any + * needed request body data before writing the response. Once the + * headers have been flushed (due to either an explicit Flusher.Flush + * call or writing enough data to trigger a flush), the request body + * may be unavailable. For HTTP/2 requests, the Go HTTP server permits + * handlers to continue to read the request body while concurrently + * writing the response. However, such behavior may not be supported + * by all HTTP/2 clients. Handlers should read before writing if + * possible to maximize compatibility. */ - writeString(s: string): number - } - interface Writer { + write(_arg0: string|Array): number /** - * ReadFrom implements [io.ReaderFrom]. If the underlying writer - * supports the ReadFrom method, this calls the underlying ReadFrom. - * If there is buffered data and an underlying ReadFrom, this fills - * the buffer and writes it before calling ReadFrom. + * WriteHeader sends an HTTP response header with the provided + * status code. + * + * If WriteHeader is not called explicitly, the first call to Write + * will trigger an implicit WriteHeader(http.StatusOK). + * Thus explicit calls to WriteHeader are mainly used to + * send error codes or 1xx informational responses. + * + * The provided code must be a valid HTTP 1xx-5xx status code. + * Any number of 1xx headers may be written, followed by at most + * one 2xx-5xx header. 1xx headers are sent immediately, but 2xx-5xx + * headers may be buffered. Use the Flusher interface to send + * buffered data. The header map is cleared when 2xx-5xx headers are + * sent, but not with 1xx headers. + * + * The server will automatically send a 100 (Continue) header + * on the first read from the request body if the request has + * an "Expect: 100-continue" header. */ - readFrom(r: io.Reader): number + writeHeader(statusCode: number): void } -} - -namespace search { -} - -/** - * Package mail implements parsing of mail messages. - * - * For the most part, this package follows the syntax as specified by RFC 5322 and - * extended by RFC 6532. - * Notable divergences: - * ``` - * - Obsolete address formats are not parsed, including addresses with - * embedded route information. - * - The full range of spacing (the CFWS syntax element) is not supported, - * such as breaking addresses across lines. - * - No unicode normalization is performed. - * - A leading From line is permitted, as in mbox format (RFC 4155). - * ``` - */ -namespace mail { /** - * Address represents a single mail address. - * An address such as "Barry Gibbs " is represented - * as Address{Name: "Barry Gibbs", Address: "bg@example.com"}. + * A Server defines parameters for running an HTTP server. + * The zero value for Server is a valid configuration. */ - interface Address { - name: string // Proper name; may be empty. - address: string // user@domain - } - interface Address { + interface Server { /** - * String formats the address as a valid RFC 5322 address. - * If the address's name contains non-ASCII characters - * the name will be rendered according to RFC 2047. + * Addr optionally specifies the TCP address for the server to listen on, + * in the form "host:port". If empty, ":http" (port 80) is used. + * The service names are defined in RFC 6335 and assigned by IANA. + * See net.Dial for details of the address format. */ - string(): string - } -} - -/** - * Package slog provides structured logging, - * in which log records include a message, - * a severity level, and various other attributes - * expressed as key-value pairs. - * - * It defines a type, [Logger], - * which provides several methods (such as [Logger.Info] and [Logger.Error]) - * for reporting events of interest. - * - * Each Logger is associated with a [Handler]. - * A Logger output method creates a [Record] from the method arguments - * and passes it to the Handler, which decides how to handle it. - * There is a default Logger accessible through top-level functions - * (such as [Info] and [Error]) that call the corresponding Logger methods. - * - * A log record consists of a time, a level, a message, and a set of key-value - * pairs, where the keys are strings and the values may be of any type. - * As an example, - * - * ``` - * slog.Info("hello", "count", 3) - * ``` - * - * creates a record containing the time of the call, - * a level of Info, the message "hello", and a single - * pair with key "count" and value 3. - * - * The [Info] top-level function calls the [Logger.Info] method on the default Logger. - * In addition to [Logger.Info], there are methods for Debug, Warn and Error levels. - * Besides these convenience methods for common levels, - * there is also a [Logger.Log] method which takes the level as an argument. - * Each of these methods has a corresponding top-level function that uses the - * default logger. - * - * The default handler formats the log record's message, time, level, and attributes - * as a string and passes it to the [log] package. - * - * ``` - * 2022/11/08 15:28:26 INFO hello count=3 - * ``` - * - * For more control over the output format, create a logger with a different handler. - * This statement uses [New] to create a new logger with a [TextHandler] - * that writes structured records in text form to standard error: - * - * ``` - * logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) - * ``` - * - * [TextHandler] output is a sequence of key=value pairs, easily and unambiguously - * parsed by machine. This statement: - * - * ``` - * logger.Info("hello", "count", 3) - * ``` - * - * produces this output: - * - * ``` - * time=2022-11-08T15:28:26.000-05:00 level=INFO msg=hello count=3 - * ``` - * - * The package also provides [JSONHandler], whose output is line-delimited JSON: - * - * ``` - * logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) - * logger.Info("hello", "count", 3) - * ``` - * - * produces this output: - * - * ``` - * {"time":"2022-11-08T15:28:26.000000000-05:00","level":"INFO","msg":"hello","count":3} - * ``` - * - * Both [TextHandler] and [JSONHandler] can be configured with [HandlerOptions]. - * There are options for setting the minimum level (see Levels, below), - * displaying the source file and line of the log call, and - * modifying attributes before they are logged. - * - * Setting a logger as the default with - * - * ``` - * slog.SetDefault(logger) - * ``` - * - * will cause the top-level functions like [Info] to use it. - * [SetDefault] also updates the default logger used by the [log] package, - * so that existing applications that use [log.Printf] and related functions - * will send log records to the logger's handler without needing to be rewritten. - * - * Some attributes are common to many log calls. - * For example, you may wish to include the URL or trace identifier of a server request - * with all log events arising from the request. - * Rather than repeat the attribute with every log call, you can use [Logger.With] - * to construct a new Logger containing the attributes: - * - * ``` - * logger2 := logger.With("url", r.URL) - * ``` - * - * The arguments to With are the same key-value pairs used in [Logger.Info]. - * The result is a new Logger with the same handler as the original, but additional - * attributes that will appear in the output of every call. - * - * # Levels - * - * A [Level] is an integer representing the importance or severity of a log event. - * The higher the level, the more severe the event. - * This package defines constants for the most common levels, - * but any int can be used as a level. - * - * In an application, you may wish to log messages only at a certain level or greater. - * One common configuration is to log messages at Info or higher levels, - * suppressing debug logging until it is needed. - * The built-in handlers can be configured with the minimum level to output by - * setting [HandlerOptions.Level]. - * The program's `main` function typically does this. - * The default value is LevelInfo. - * - * Setting the [HandlerOptions.Level] field to a [Level] value - * fixes the handler's minimum level throughout its lifetime. - * Setting it to a [LevelVar] allows the level to be varied dynamically. - * A LevelVar holds a Level and is safe to read or write from multiple - * goroutines. - * To vary the level dynamically for an entire program, first initialize - * a global LevelVar: - * - * ``` - * var programLevel = new(slog.LevelVar) // Info by default - * ``` - * - * Then use the LevelVar to construct a handler, and make it the default: - * - * ``` - * h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}) - * slog.SetDefault(slog.New(h)) - * ``` - * - * Now the program can change its logging level with a single statement: - * - * ``` - * programLevel.Set(slog.LevelDebug) - * ``` - * - * # Groups - * - * Attributes can be collected into groups. - * A group has a name that is used to qualify the names of its attributes. - * How this qualification is displayed depends on the handler. - * [TextHandler] separates the group and attribute names with a dot. - * [JSONHandler] treats each group as a separate JSON object, with the group name as the key. - * - * Use [Group] to create a Group attribute from a name and a list of key-value pairs: - * - * ``` - * slog.Group("request", - * "method", r.Method, - * "url", r.URL) - * ``` - * - * TextHandler would display this group as - * - * ``` - * request.method=GET request.url=http://example.com - * ``` - * - * JSONHandler would display it as - * - * ``` - * "request":{"method":"GET","url":"http://example.com"} - * ``` - * - * Use [Logger.WithGroup] to qualify all of a Logger's output - * with a group name. Calling WithGroup on a Logger results in a - * new Logger with the same Handler as the original, but with all - * its attributes qualified by the group name. - * - * This can help prevent duplicate attribute keys in large systems, - * where subsystems might use the same keys. - * Pass each subsystem a different Logger with its own group name so that - * potential duplicates are qualified: - * - * ``` - * logger := slog.Default().With("id", systemID) - * parserLogger := logger.WithGroup("parser") - * parseInput(input, parserLogger) - * ``` - * - * When parseInput logs with parserLogger, its keys will be qualified with "parser", - * so even if it uses the common key "id", the log line will have distinct keys. - * - * # Contexts - * - * Some handlers may wish to include information from the [context.Context] that is - * available at the call site. One example of such information - * is the identifier for the current span when tracing is enabled. - * - * The [Logger.Log] and [Logger.LogAttrs] methods take a context as a first - * argument, as do their corresponding top-level functions. - * - * Although the convenience methods on Logger (Info and so on) and the - * corresponding top-level functions do not take a context, the alternatives ending - * in "Context" do. For example, - * - * ``` - * slog.InfoContext(ctx, "message") - * ``` - * - * It is recommended to pass a context to an output method if one is available. - * - * # Attrs and Values - * - * An [Attr] is a key-value pair. The Logger output methods accept Attrs as well as - * alternating keys and values. The statement - * - * ``` - * slog.Info("hello", slog.Int("count", 3)) - * ``` - * - * behaves the same as - * - * ``` - * slog.Info("hello", "count", 3) - * ``` - * - * There are convenience constructors for [Attr] such as [Int], [String], and [Bool] - * for common types, as well as the function [Any] for constructing Attrs of any - * type. - * - * The value part of an Attr is a type called [Value]. - * Like an [any], a Value can hold any Go value, - * but it can represent typical values, including all numbers and strings, - * without an allocation. - * - * For the most efficient log output, use [Logger.LogAttrs]. - * It is similar to [Logger.Log] but accepts only Attrs, not alternating - * keys and values; this allows it, too, to avoid allocation. - * - * The call - * - * ``` - * logger.LogAttrs(ctx, slog.LevelInfo, "hello", slog.Int("count", 3)) - * ``` - * - * is the most efficient way to achieve the same output as - * - * ``` - * slog.InfoContext(ctx, "hello", "count", 3) - * ``` - * - * # Customizing a type's logging behavior - * - * If a type implements the [LogValuer] interface, the [Value] returned from its LogValue - * method is used for logging. You can use this to control how values of the type - * appear in logs. For example, you can redact secret information like passwords, - * or gather a struct's fields in a Group. See the examples under [LogValuer] for - * details. - * - * A LogValue method may return a Value that itself implements [LogValuer]. The [Value.Resolve] - * method handles these cases carefully, avoiding infinite loops and unbounded recursion. - * Handler authors and others may wish to use [Value.Resolve] instead of calling LogValue directly. - * - * # Wrapping output methods - * - * The logger functions use reflection over the call stack to find the file name - * and line number of the logging call within the application. This can produce - * incorrect source information for functions that wrap slog. For instance, if you - * define this function in file mylog.go: - * - * ``` - * func Infof(logger *slog.Logger, format string, args ...any) { - * logger.Info(fmt.Sprintf(format, args...)) - * } - * ``` - * - * and you call it like this in main.go: - * - * ``` - * Infof(slog.Default(), "hello, %s", "world") - * ``` - * - * then slog will report the source file as mylog.go, not main.go. - * - * A correct implementation of Infof will obtain the source location - * (pc) and pass it to NewRecord. - * The Infof function in the package-level example called "wrapping" - * demonstrates how to do this. - * - * # Working with Records - * - * Sometimes a Handler will need to modify a Record - * before passing it on to another Handler or backend. - * A Record contains a mixture of simple public fields (e.g. Time, Level, Message) - * and hidden fields that refer to state (such as attributes) indirectly. This - * means that modifying a simple copy of a Record (e.g. by calling - * [Record.Add] or [Record.AddAttrs] to add attributes) - * may have unexpected effects on the original. - * Before modifying a Record, use [Record.Clone] to - * create a copy that shares no state with the original, - * or create a new Record with [NewRecord] - * and build up its Attrs by traversing the old ones with [Record.Attrs]. - * - * # Performance considerations - * - * If profiling your application demonstrates that logging is taking significant time, - * the following suggestions may help. - * - * If many log lines have a common attribute, use [Logger.With] to create a Logger with - * that attribute. The built-in handlers will format that attribute only once, at the - * call to [Logger.With]. The [Handler] interface is designed to allow that optimization, - * and a well-written Handler should take advantage of it. - * - * The arguments to a log call are always evaluated, even if the log event is discarded. - * If possible, defer computation so that it happens only if the value is actually logged. - * For example, consider the call - * - * ``` - * slog.Info("starting request", "url", r.URL.String()) // may compute String unnecessarily - * ``` - * - * The URL.String method will be called even if the logger discards Info-level events. - * Instead, pass the URL directly: - * - * ``` - * slog.Info("starting request", "url", &r.URL) // calls URL.String only if needed - * ``` - * - * The built-in [TextHandler] will call its String method, but only - * if the log event is enabled. - * Avoiding the call to String also preserves the structure of the underlying value. - * For example [JSONHandler] emits the components of the parsed URL as a JSON object. - * If you want to avoid eagerly paying the cost of the String call - * without causing the handler to potentially inspect the structure of the value, - * wrap the value in a fmt.Stringer implementation that hides its Marshal methods. - * - * You can also use the [LogValuer] interface to avoid unnecessary work in disabled log - * calls. Say you need to log some expensive value: - * - * ``` - * slog.Debug("frobbing", "value", computeExpensiveValue(arg)) - * ``` - * - * Even if this line is disabled, computeExpensiveValue will be called. - * To avoid that, define a type implementing LogValuer: - * - * ``` - * type expensive struct { arg int } - * - * func (e expensive) LogValue() slog.Value { - * return slog.AnyValue(computeExpensiveValue(e.arg)) - * } - * ``` - * - * Then use a value of that type in log calls: - * - * ``` - * slog.Debug("frobbing", "value", expensive{arg}) - * ``` - * - * Now computeExpensiveValue will only be called when the line is enabled. - * - * The built-in handlers acquire a lock before calling [io.Writer.Write] - * to ensure that exactly one [Record] is written at a time in its entirety. - * Although each log record has a timestamp, - * the built-in handlers do not use that time to sort the written records. - * User-defined handlers are responsible for their own locking and sorting. - * - * # Writing a handler - * - * For a guide to writing a custom handler, see https://golang.org/s/slog-handler-guide. - */ -namespace slog { - // @ts-ignore - import loginternal = internal - /** - * A Record holds information about a log event. - * Copies of a Record share state. - * Do not modify a Record after handing out a copy to it. - * Call [NewRecord] to create a new Record. - * Use [Record.Clone] to create a copy with no shared state. - */ - interface Record { - /** - * The time at which the output method (Log, Info, etc.) was called. - */ - time: time.Time - /** - * The log message. - */ - message: string - /** - * The level of the event. - */ - level: Level - /** - * The program counter at the time the record was constructed, as determined - * by runtime.Callers. If zero, no program counter is available. - * - * The only valid use for this value is as an argument to - * [runtime.CallersFrames]. In particular, it must not be passed to - * [runtime.FuncForPC]. - */ - pc: number - } - interface Record { - /** - * Clone returns a copy of the record with no shared state. - * The original record and the clone can both be modified - * without interfering with each other. - */ - clone(): Record - } - interface Record { - /** - * NumAttrs returns the number of attributes in the [Record]. - */ - numAttrs(): number - } - interface Record { - /** - * Attrs calls f on each Attr in the [Record]. - * Iteration stops if f returns false. - */ - attrs(f: (_arg0: Attr) => boolean): void - } - interface Record { - /** - * AddAttrs appends the given Attrs to the [Record]'s list of Attrs. - * It omits empty groups. - */ - addAttrs(...attrs: Attr[]): void - } - interface Record { - /** - * Add converts the args to Attrs as described in [Logger.Log], - * then appends the Attrs to the [Record]'s list of Attrs. - * It omits empty groups. - */ - add(...args: any[]): void - } - /** - * A Value can represent any Go value, but unlike type any, - * it can represent most small values without an allocation. - * The zero Value corresponds to nil. - */ - interface Value { - } - interface Value { - /** - * Kind returns v's Kind. - */ - kind(): Kind - } - interface Value { - /** - * Any returns v's value as an any. - */ - any(): any - } - interface Value { - /** - * String returns Value's value as a string, formatted like [fmt.Sprint]. Unlike - * the methods Int64, Float64, and so on, which panic if v is of the - * wrong kind, String never panics. - */ - string(): string - } - interface Value { - /** - * Int64 returns v's value as an int64. It panics - * if v is not a signed integer. - */ - int64(): number - } - interface Value { - /** - * Uint64 returns v's value as a uint64. It panics - * if v is not an unsigned integer. - */ - uint64(): number - } - interface Value { - /** - * Bool returns v's value as a bool. It panics - * if v is not a bool. - */ - bool(): boolean - } - interface Value { - /** - * Duration returns v's value as a [time.Duration]. It panics - * if v is not a time.Duration. - */ - duration(): time.Duration - } - interface Value { - /** - * Float64 returns v's value as a float64. It panics - * if v is not a float64. - */ - float64(): number - } - interface Value { - /** - * Time returns v's value as a [time.Time]. It panics - * if v is not a time.Time. - */ - time(): time.Time - } - interface Value { - /** - * LogValuer returns v's value as a LogValuer. It panics - * if v is not a LogValuer. - */ - logValuer(): LogValuer - } - interface Value { - /** - * Group returns v's value as a []Attr. - * It panics if v's [Kind] is not [KindGroup]. - */ - group(): Array - } - interface Value { - /** - * Equal reports whether v and w represent the same Go value. - */ - equal(w: Value): boolean - } - interface Value { - /** - * Resolve repeatedly calls LogValue on v while it implements [LogValuer], - * and returns the result. - * If v resolves to a group, the group's attributes' values are not recursively - * resolved. - * If the number of LogValue calls exceeds a threshold, a Value containing an - * error is returned. - * Resolve's return value is guaranteed not to be of Kind [KindLogValuer]. - */ - resolve(): Value - } -} - -namespace subscriptions { -} - -/** - * Package slog provides structured logging, - * in which log records include a message, - * a severity level, and various other attributes - * expressed as key-value pairs. - * - * It defines a type, [Logger], - * which provides several methods (such as [Logger.Info] and [Logger.Error]) - * for reporting events of interest. - * - * Each Logger is associated with a [Handler]. - * A Logger output method creates a [Record] from the method arguments - * and passes it to the Handler, which decides how to handle it. - * There is a default Logger accessible through top-level functions - * (such as [Info] and [Error]) that call the corresponding Logger methods. - * - * A log record consists of a time, a level, a message, and a set of key-value - * pairs, where the keys are strings and the values may be of any type. - * As an example, - * - * ``` - * slog.Info("hello", "count", 3) - * ``` - * - * creates a record containing the time of the call, - * a level of Info, the message "hello", and a single - * pair with key "count" and value 3. - * - * The [Info] top-level function calls the [Logger.Info] method on the default Logger. - * In addition to [Logger.Info], there are methods for Debug, Warn and Error levels. - * Besides these convenience methods for common levels, - * there is also a [Logger.Log] method which takes the level as an argument. - * Each of these methods has a corresponding top-level function that uses the - * default logger. - * - * The default handler formats the log record's message, time, level, and attributes - * as a string and passes it to the [log] package. - * - * ``` - * 2022/11/08 15:28:26 INFO hello count=3 - * ``` - * - * For more control over the output format, create a logger with a different handler. - * This statement uses [New] to create a new logger with a [TextHandler] - * that writes structured records in text form to standard error: - * - * ``` - * logger := slog.New(slog.NewTextHandler(os.Stderr, nil)) - * ``` - * - * [TextHandler] output is a sequence of key=value pairs, easily and unambiguously - * parsed by machine. This statement: - * - * ``` - * logger.Info("hello", "count", 3) - * ``` - * - * produces this output: - * - * ``` - * time=2022-11-08T15:28:26.000-05:00 level=INFO msg=hello count=3 - * ``` - * - * The package also provides [JSONHandler], whose output is line-delimited JSON: - * - * ``` - * logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) - * logger.Info("hello", "count", 3) - * ``` - * - * produces this output: - * - * ``` - * {"time":"2022-11-08T15:28:26.000000000-05:00","level":"INFO","msg":"hello","count":3} - * ``` - * - * Both [TextHandler] and [JSONHandler] can be configured with [HandlerOptions]. - * There are options for setting the minimum level (see Levels, below), - * displaying the source file and line of the log call, and - * modifying attributes before they are logged. - * - * Setting a logger as the default with - * - * ``` - * slog.SetDefault(logger) - * ``` - * - * will cause the top-level functions like [Info] to use it. - * [SetDefault] also updates the default logger used by the [log] package, - * so that existing applications that use [log.Printf] and related functions - * will send log records to the logger's handler without needing to be rewritten. - * - * Some attributes are common to many log calls. - * For example, you may wish to include the URL or trace identifier of a server request - * with all log events arising from the request. - * Rather than repeat the attribute with every log call, you can use [Logger.With] - * to construct a new Logger containing the attributes: - * - * ``` - * logger2 := logger.With("url", r.URL) - * ``` - * - * The arguments to With are the same key-value pairs used in [Logger.Info]. - * The result is a new Logger with the same handler as the original, but additional - * attributes that will appear in the output of every call. - * - * # Levels - * - * A [Level] is an integer representing the importance or severity of a log event. - * The higher the level, the more severe the event. - * This package defines constants for the most common levels, - * but any int can be used as a level. - * - * In an application, you may wish to log messages only at a certain level or greater. - * One common configuration is to log messages at Info or higher levels, - * suppressing debug logging until it is needed. - * The built-in handlers can be configured with the minimum level to output by - * setting [HandlerOptions.Level]. - * The program's `main` function typically does this. - * The default value is LevelInfo. - * - * Setting the [HandlerOptions.Level] field to a [Level] value - * fixes the handler's minimum level throughout its lifetime. - * Setting it to a [LevelVar] allows the level to be varied dynamically. - * A LevelVar holds a Level and is safe to read or write from multiple - * goroutines. - * To vary the level dynamically for an entire program, first initialize - * a global LevelVar: - * - * ``` - * var programLevel = new(slog.LevelVar) // Info by default - * ``` - * - * Then use the LevelVar to construct a handler, and make it the default: - * - * ``` - * h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel}) - * slog.SetDefault(slog.New(h)) - * ``` - * - * Now the program can change its logging level with a single statement: - * - * ``` - * programLevel.Set(slog.LevelDebug) - * ``` - * - * # Groups - * - * Attributes can be collected into groups. - * A group has a name that is used to qualify the names of its attributes. - * How this qualification is displayed depends on the handler. - * [TextHandler] separates the group and attribute names with a dot. - * [JSONHandler] treats each group as a separate JSON object, with the group name as the key. - * - * Use [Group] to create a Group attribute from a name and a list of key-value pairs: - * - * ``` - * slog.Group("request", - * "method", r.Method, - * "url", r.URL) - * ``` - * - * TextHandler would display this group as - * - * ``` - * request.method=GET request.url=http://example.com - * ``` - * - * JSONHandler would display it as - * - * ``` - * "request":{"method":"GET","url":"http://example.com"} - * ``` - * - * Use [Logger.WithGroup] to qualify all of a Logger's output - * with a group name. Calling WithGroup on a Logger results in a - * new Logger with the same Handler as the original, but with all - * its attributes qualified by the group name. - * - * This can help prevent duplicate attribute keys in large systems, - * where subsystems might use the same keys. - * Pass each subsystem a different Logger with its own group name so that - * potential duplicates are qualified: - * - * ``` - * logger := slog.Default().With("id", systemID) - * parserLogger := logger.WithGroup("parser") - * parseInput(input, parserLogger) - * ``` - * - * When parseInput logs with parserLogger, its keys will be qualified with "parser", - * so even if it uses the common key "id", the log line will have distinct keys. - * - * # Contexts - * - * Some handlers may wish to include information from the [context.Context] that is - * available at the call site. One example of such information - * is the identifier for the current span when tracing is enabled. - * - * The [Logger.Log] and [Logger.LogAttrs] methods take a context as a first - * argument, as do their corresponding top-level functions. - * - * Although the convenience methods on Logger (Info and so on) and the - * corresponding top-level functions do not take a context, the alternatives ending - * in "Context" do. For example, - * - * ``` - * slog.InfoContext(ctx, "message") - * ``` - * - * It is recommended to pass a context to an output method if one is available. - * - * # Attrs and Values - * - * An [Attr] is a key-value pair. The Logger output methods accept Attrs as well as - * alternating keys and values. The statement - * - * ``` - * slog.Info("hello", slog.Int("count", 3)) - * ``` - * - * behaves the same as - * - * ``` - * slog.Info("hello", "count", 3) - * ``` - * - * There are convenience constructors for [Attr] such as [Int], [String], and [Bool] - * for common types, as well as the function [Any] for constructing Attrs of any - * type. - * - * The value part of an Attr is a type called [Value]. - * Like an [any], a Value can hold any Go value, - * but it can represent typical values, including all numbers and strings, - * without an allocation. - * - * For the most efficient log output, use [Logger.LogAttrs]. - * It is similar to [Logger.Log] but accepts only Attrs, not alternating - * keys and values; this allows it, too, to avoid allocation. - * - * The call - * - * ``` - * logger.LogAttrs(ctx, slog.LevelInfo, "hello", slog.Int("count", 3)) - * ``` - * - * is the most efficient way to achieve the same output as - * - * ``` - * slog.InfoContext(ctx, "hello", "count", 3) - * ``` - * - * # Customizing a type's logging behavior - * - * If a type implements the [LogValuer] interface, the [Value] returned from its LogValue - * method is used for logging. You can use this to control how values of the type - * appear in logs. For example, you can redact secret information like passwords, - * or gather a struct's fields in a Group. See the examples under [LogValuer] for - * details. - * - * A LogValue method may return a Value that itself implements [LogValuer]. The [Value.Resolve] - * method handles these cases carefully, avoiding infinite loops and unbounded recursion. - * Handler authors and others may wish to use [Value.Resolve] instead of calling LogValue directly. - * - * # Wrapping output methods - * - * The logger functions use reflection over the call stack to find the file name - * and line number of the logging call within the application. This can produce - * incorrect source information for functions that wrap slog. For instance, if you - * define this function in file mylog.go: - * - * ``` - * func Infof(logger *slog.Logger, format string, args ...any) { - * logger.Info(fmt.Sprintf(format, args...)) - * } - * ``` - * - * and you call it like this in main.go: - * - * ``` - * Infof(slog.Default(), "hello, %s", "world") - * ``` - * - * then slog will report the source file as mylog.go, not main.go. - * - * A correct implementation of Infof will obtain the source location - * (pc) and pass it to NewRecord. - * The Infof function in the package-level example called "wrapping" - * demonstrates how to do this. - * - * # Working with Records - * - * Sometimes a Handler will need to modify a Record - * before passing it on to another Handler or backend. - * A Record contains a mixture of simple public fields (e.g. Time, Level, Message) - * and hidden fields that refer to state (such as attributes) indirectly. This - * means that modifying a simple copy of a Record (e.g. by calling - * [Record.Add] or [Record.AddAttrs] to add attributes) - * may have unexpected effects on the original. - * Before modifying a Record, use [Record.Clone] to - * create a copy that shares no state with the original, - * or create a new Record with [NewRecord] - * and build up its Attrs by traversing the old ones with [Record.Attrs]. - * - * # Performance considerations - * - * If profiling your application demonstrates that logging is taking significant time, - * the following suggestions may help. - * - * If many log lines have a common attribute, use [Logger.With] to create a Logger with - * that attribute. The built-in handlers will format that attribute only once, at the - * call to [Logger.With]. The [Handler] interface is designed to allow that optimization, - * and a well-written Handler should take advantage of it. - * - * The arguments to a log call are always evaluated, even if the log event is discarded. - * If possible, defer computation so that it happens only if the value is actually logged. - * For example, consider the call - * - * ``` - * slog.Info("starting request", "url", r.URL.String()) // may compute String unnecessarily - * ``` - * - * The URL.String method will be called even if the logger discards Info-level events. - * Instead, pass the URL directly: - * - * ``` - * slog.Info("starting request", "url", &r.URL) // calls URL.String only if needed - * ``` - * - * The built-in [TextHandler] will call its String method, but only - * if the log event is enabled. - * Avoiding the call to String also preserves the structure of the underlying value. - * For example [JSONHandler] emits the components of the parsed URL as a JSON object. - * If you want to avoid eagerly paying the cost of the String call - * without causing the handler to potentially inspect the structure of the value, - * wrap the value in a fmt.Stringer implementation that hides its Marshal methods. - * - * You can also use the [LogValuer] interface to avoid unnecessary work in disabled log - * calls. Say you need to log some expensive value: - * - * ``` - * slog.Debug("frobbing", "value", computeExpensiveValue(arg)) - * ``` + addr: string + handler: Handler // handler to invoke, http.DefaultServeMux if nil + /** + * DisableGeneralOptionsHandler, if true, passes "OPTIONS *" requests to the Handler, + * otherwise responds with 200 OK and Content-Length: 0. + */ + disableGeneralOptionsHandler: boolean + /** + * TLSConfig optionally provides a TLS configuration for use + * by ServeTLS and ListenAndServeTLS. Note that this value is + * cloned by ServeTLS and ListenAndServeTLS, so it's not + * possible to modify the configuration with methods like + * tls.Config.SetSessionTicketKeys. To use + * SetSessionTicketKeys, use Server.Serve with a TLS Listener + * instead. + */ + tlsConfig?: any + /** + * ReadTimeout is the maximum duration for reading the entire + * request, including the body. A zero or negative value means + * there will be no timeout. + * + * Because ReadTimeout does not let Handlers make per-request + * decisions on each request body's acceptable deadline or + * upload rate, most users will prefer to use + * ReadHeaderTimeout. It is valid to use them both. + */ + readTimeout: time.Duration + /** + * ReadHeaderTimeout is the amount of time allowed to read + * request headers. The connection's read deadline is reset + * after reading the headers and the Handler can decide what + * is considered too slow for the body. If zero, the value of + * ReadTimeout is used. If negative, or if zero and ReadTimeout + * is zero or negative, there is no timeout. + */ + readHeaderTimeout: time.Duration + /** + * WriteTimeout is the maximum duration before timing out + * writes of the response. It is reset whenever a new + * request's header is read. Like ReadTimeout, it does not + * let Handlers make decisions on a per-request basis. + * A zero or negative value means there will be no timeout. + */ + writeTimeout: time.Duration + /** + * IdleTimeout is the maximum amount of time to wait for the + * next request when keep-alives are enabled. If zero, the value + * of ReadTimeout is used. If negative, or if zero and ReadTimeout + * is zero or negative, there is no timeout. + */ + idleTimeout: time.Duration + /** + * MaxHeaderBytes controls the maximum number of bytes the + * server will read parsing the request header's keys and + * values, including the request line. It does not limit the + * size of the request body. + * If zero, DefaultMaxHeaderBytes is used. + */ + maxHeaderBytes: number + /** + * TLSNextProto optionally specifies a function to take over + * ownership of the provided TLS connection when an ALPN + * protocol upgrade has occurred. The map key is the protocol + * name negotiated. The Handler argument should be used to + * handle HTTP requests and will initialize the Request's TLS + * and RemoteAddr if not already set. The connection is + * automatically closed when the function returns. + * If TLSNextProto is not nil, HTTP/2 support is not enabled + * automatically. + */ + tlsNextProto: _TygojaDict + /** + * ConnState specifies an optional callback function that is + * called when a client connection changes state. See the + * ConnState type and associated constants for details. + */ + connState: (_arg0: net.Conn, _arg1: ConnState) => void + /** + * ErrorLog specifies an optional logger for errors accepting + * connections, unexpected behavior from handlers, and + * underlying FileSystem errors. + * If nil, logging is done via the log package's standard logger. + */ + errorLog?: any + /** + * BaseContext optionally specifies a function that returns + * the base context for incoming requests on this server. + * The provided Listener is the specific Listener that's + * about to start accepting requests. + * If BaseContext is nil, the default is context.Background(). + * If non-nil, it must return a non-nil context. + */ + baseContext: (_arg0: net.Listener) => context.Context + /** + * ConnContext optionally specifies a function that modifies + * the context used for a new connection c. The provided ctx + * is derived from the base context and has a ServerContextKey + * value. + */ + connContext: (ctx: context.Context, c: net.Conn) => context.Context + /** + * HTTP2 configures HTTP/2 connections. + * + * This field does not yet have any effect. + * See https://go.dev/issue/67813. + */ + http2?: HTTP2Config + /** + * Protocols is the set of protocols accepted by the server. + * + * If Protocols includes UnencryptedHTTP2, the server will accept + * unencrypted HTTP/2 connections. The server can serve both + * HTTP/1 and unencrypted HTTP/2 on the same address and port. + * + * If Protocols is nil, the default is usually HTTP/1 and HTTP/2. + * If TLSNextProto is non-nil and does not contain an "h2" entry, + * the default is HTTP/1 only. + */ + protocols?: Protocols + } + interface Server { + /** + * Close immediately closes all active net.Listeners and any + * connections in state [StateNew], [StateActive], or [StateIdle]. For a + * graceful shutdown, use [Server.Shutdown]. + * + * Close does not attempt to close (and does not even know about) + * any hijacked connections, such as WebSockets. + * + * Close returns any error returned from closing the [Server]'s + * underlying Listener(s). + */ + close(): void + } + interface Server { + /** + * Shutdown gracefully shuts down the server without interrupting any + * active connections. Shutdown works by first closing all open + * listeners, then closing all idle connections, and then waiting + * indefinitely for connections to return to idle and then shut down. + * If the provided context expires before the shutdown is complete, + * Shutdown returns the context's error, otherwise it returns any + * error returned from closing the [Server]'s underlying Listener(s). + * + * When Shutdown is called, [Serve], [ListenAndServe], and + * [ListenAndServeTLS] immediately return [ErrServerClosed]. Make sure the + * program doesn't exit and waits instead for Shutdown to return. + * + * Shutdown does not attempt to close nor wait for hijacked + * connections such as WebSockets. The caller of Shutdown should + * separately notify such long-lived connections of shutdown and wait + * for them to close, if desired. See [Server.RegisterOnShutdown] for a way to + * register shutdown notification functions. + * + * Once Shutdown has been called on a server, it may not be reused; + * future calls to methods such as Serve will return ErrServerClosed. + */ + shutdown(ctx: context.Context): void + } + interface Server { + /** + * RegisterOnShutdown registers a function to call on [Server.Shutdown]. + * This can be used to gracefully shutdown connections that have + * undergone ALPN protocol upgrade or that have been hijacked. + * This function should start protocol-specific graceful shutdown, + * but should not wait for shutdown to complete. + */ + registerOnShutdown(f: () => void): void + } + interface Server { + /** + * ListenAndServe listens on the TCP network address s.Addr and then + * calls [Serve] to handle requests on incoming connections. + * Accepted connections are configured to enable TCP keep-alives. + * + * If s.Addr is blank, ":http" is used. + * + * ListenAndServe always returns a non-nil error. After [Server.Shutdown] or [Server.Close], + * the returned error is [ErrServerClosed]. + */ + listenAndServe(): void + } + interface Server { + /** + * Serve accepts incoming connections on the Listener l, creating a + * new service goroutine for each. The service goroutines read requests and + * then call s.Handler to reply to them. + * + * HTTP/2 support is only enabled if the Listener returns [*tls.Conn] + * connections and they were configured with "h2" in the TLS + * Config.NextProtos. + * + * Serve always returns a non-nil error and closes l. + * After [Server.Shutdown] or [Server.Close], the returned error is [ErrServerClosed]. + */ + serve(l: net.Listener): void + } + interface Server { + /** + * ServeTLS accepts incoming connections on the Listener l, creating a + * new service goroutine for each. The service goroutines perform TLS + * setup and then read requests, calling s.Handler to reply to them. + * + * Files containing a certificate and matching private key for the + * server must be provided if neither the [Server]'s + * TLSConfig.Certificates, TLSConfig.GetCertificate nor + * config.GetConfigForClient are populated. + * If the certificate is signed by a certificate authority, the + * certFile should be the concatenation of the server's certificate, + * any intermediates, and the CA's certificate. + * + * ServeTLS always returns a non-nil error. After [Server.Shutdown] or [Server.Close], the + * returned error is [ErrServerClosed]. + */ + serveTLS(l: net.Listener, certFile: string, keyFile: string): void + } + interface Server { + /** + * SetKeepAlivesEnabled controls whether HTTP keep-alives are enabled. + * By default, keep-alives are always enabled. Only very + * resource-constrained environments or servers in the process of + * shutting down should disable them. + */ + setKeepAlivesEnabled(v: boolean): void + } + interface Server { + /** + * ListenAndServeTLS listens on the TCP network address s.Addr and + * then calls [ServeTLS] to handle requests on incoming TLS connections. + * Accepted connections are configured to enable TCP keep-alives. + * + * Filenames containing a certificate and matching private key for the + * server must be provided if neither the [Server]'s TLSConfig.Certificates + * nor TLSConfig.GetCertificate are populated. If the certificate is + * signed by a certificate authority, the certFile should be the + * concatenation of the server's certificate, any intermediates, and + * the CA's certificate. + * + * If s.Addr is blank, ":https" is used. + * + * ListenAndServeTLS always returns a non-nil error. After [Server.Shutdown] or + * [Server.Close], the returned error is [ErrServerClosed]. + */ + listenAndServeTLS(certFile: string, keyFile: string): void + } +} + +/** + * Package blob defines a lightweight abstration for interacting with + * various storage services (local filesystem, S3, etc.). + * + * NB! + * For compatibility with earlier PocketBase versions and to prevent + * unnecessary breaking changes, this package is based and implemented + * as a minimal, stripped down version of the previously used gocloud.dev/blob. + * While there is no promise that it won't diverge in the future to accommodate + * better some PocketBase specific use cases, currently it copies and + * tries to follow as close as possible the same implementations, + * conventions and rules for the key escaping/unescaping, blob read/write + * interfaces and struct options as gocloud.dev/blob, therefore the + * credits goes to the original Go Cloud Development Kit Authors. + */ +namespace blob { + /** + * ListObject represents a single blob returned from List. + */ + interface ListObject { + /** + * Key is the key for this blob. + */ + key: string + /** + * ModTime is the time the blob was last modified. + */ + modTime: time.Time + /** + * Size is the size of the blob's content in bytes. + */ + size: number + /** + * MD5 is an MD5 hash of the blob contents or nil if not available. + */ + md5: string|Array + /** + * IsDir indicates that this result represents a "directory" in the + * hierarchical namespace, ending in ListOptions.Delimiter. Key can be + * passed as ListOptions.Prefix to list items in the "directory". + * Fields other than Key and IsDir will not be set if IsDir is true. + */ + isDir: boolean + } + /** + * Attributes contains attributes about a blob. + */ + interface Attributes { + /** + * CacheControl specifies caching attributes that services may use + * when serving the blob. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control + */ + cacheControl: string + /** + * ContentDisposition specifies whether the blob content is expected to be + * displayed inline or as an attachment. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition + */ + contentDisposition: string + /** + * ContentEncoding specifies the encoding used for the blob's content, if any. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding + */ + contentEncoding: string + /** + * ContentLanguage specifies the language used in the blob's content, if any. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Language + */ + contentLanguage: string + /** + * ContentType is the MIME type of the blob. It will not be empty. + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type + */ + contentType: string + /** + * Metadata holds key/value pairs associated with the blob. + * Keys are guaranteed to be in lowercase, even if the backend service + * has case-sensitive keys (although note that Metadata written via + * this package will always be lowercased). If there are duplicate + * case-insensitive keys (e.g., "foo" and "FOO"), only one value + * will be kept, and it is undefined which one. + */ + metadata: _TygojaDict + /** + * CreateTime is the time the blob was created, if available. If not available, + * CreateTime will be the zero time. + */ + createTime: time.Time + /** + * ModTime is the time the blob was last modified. + */ + modTime: time.Time + /** + * Size is the size of the blob's content in bytes. + */ + size: number + /** + * MD5 is an MD5 hash of the blob contents or nil if not available. + */ + md5: string|Array + /** + * ETag for the blob; see https://en.wikipedia.org/wiki/HTTP_ETag. + */ + eTag: string + } + /** + * Reader reads bytes from a blob. + * It implements io.ReadSeekCloser, and must be closed after reads are finished. + */ + interface Reader { + } + interface Reader { + /** + * Read implements io.Reader (https://golang.org/pkg/io/#Reader). + */ + read(p: string|Array): number + } + interface Reader { + /** + * Seek implements io.Seeker (https://golang.org/pkg/io/#Seeker). + */ + seek(offset: number, whence: number): number + } + interface Reader { + /** + * Close implements io.Closer (https://golang.org/pkg/io/#Closer). + */ + close(): void + } + interface Reader { + /** + * ContentType returns the MIME type of the blob. + */ + contentType(): string + } + interface Reader { + /** + * ModTime returns the time the blob was last modified. + */ + modTime(): time.Time + } + interface Reader { + /** + * Size returns the size of the blob content in bytes. + */ + size(): number + } + interface Reader { + /** + * WriteTo reads from r and writes to w until there's no more data or + * an error occurs. + * The return value is the number of bytes written to w. + * + * It implements the io.WriterTo interface. + */ + writeTo(w: io.Writer): number + } +} + +namespace exec { + /** + * Cmd represents an external command being prepared or run. + * + * A Cmd cannot be reused after calling its [Cmd.Run], [Cmd.Output] or [Cmd.CombinedOutput] + * methods. + */ + interface Cmd { + /** + * Path is the path of the command to run. + * + * This is the only field that must be set to a non-zero + * value. If Path is relative, it is evaluated relative + * to Dir. + */ + path: string + /** + * Args holds command line arguments, including the command as Args[0]. + * If the Args field is empty or nil, Run uses {Path}. + * + * In typical use, both Path and Args are set by calling Command. + */ + args: Array + /** + * Env specifies the environment of the process. + * Each entry is of the form "key=value". + * If Env is nil, the new process uses the current process's + * environment. + * If Env contains duplicate environment keys, only the last + * value in the slice for each duplicate key is used. + * As a special case on Windows, SYSTEMROOT is always added if + * missing and not explicitly set to the empty string. + * + * See also the Dir field, which may set PWD in the environment. + */ + env: Array + /** + * Dir specifies the working directory of the command. + * If Dir is the empty string, Run runs the command in the + * calling process's current directory. + * + * On Unix systems, the value of Dir also determines the + * child process's PWD environment variable if not otherwise + * specified. A Unix process represents its working directory + * not by name but as an implicit reference to a node in the + * file tree. So, if the child process obtains its working + * directory by calling a function such as C's getcwd, which + * computes the canonical name by walking up the file tree, it + * will not recover the original value of Dir if that value + * was an alias involving symbolic links. However, if the + * child process calls Go's [os.Getwd] or GNU C's + * get_current_dir_name, and the value of PWD is an alias for + * the current directory, those functions will return the + * value of PWD, which matches the value of Dir. + */ + dir: string + /** + * Stdin specifies the process's standard input. + * + * If Stdin is nil, the process reads from the null device (os.DevNull). + * + * If Stdin is an *os.File, the process's standard input is connected + * directly to that file. + * + * Otherwise, during the execution of the command a separate + * goroutine reads from Stdin and delivers that data to the command + * over a pipe. In this case, Wait does not complete until the goroutine + * stops copying, either because it has reached the end of Stdin + * (EOF or a read error), or because writing to the pipe returned an error, + * or because a nonzero WaitDelay was set and expired. + */ + stdin: io.Reader + /** + * Stdout and Stderr specify the process's standard output and error. + * + * If either is nil, Run connects the corresponding file descriptor + * to the null device (os.DevNull). + * + * If either is an *os.File, the corresponding output from the process + * is connected directly to that file. + * + * Otherwise, during the execution of the command a separate goroutine + * reads from the process over a pipe and delivers that data to the + * corresponding Writer. In this case, Wait does not complete until the + * goroutine reaches EOF or encounters an error or a nonzero WaitDelay + * expires. + * + * If Stdout and Stderr are the same writer, and have a type that can + * be compared with ==, at most one goroutine at a time will call Write. + */ + stdout: io.Writer + stderr: io.Writer + /** + * ExtraFiles specifies additional open files to be inherited by the + * new process. It does not include standard input, standard output, or + * standard error. If non-nil, entry i becomes file descriptor 3+i. + * + * ExtraFiles is not supported on Windows. + */ + extraFiles: Array<(os.File | undefined)> + /** + * SysProcAttr holds optional, operating system-specific attributes. + * Run passes it to os.StartProcess as the os.ProcAttr's Sys field. + */ + sysProcAttr?: syscall.SysProcAttr + /** + * Process is the underlying process, once started. + */ + process?: os.Process + /** + * ProcessState contains information about an exited process. + * If the process was started successfully, Wait or Run will + * populate its ProcessState when the command completes. + */ + processState?: os.ProcessState + err: Error // LookPath error, if any. + /** + * If Cancel is non-nil, the command must have been created with + * CommandContext and Cancel will be called when the command's + * Context is done. By default, CommandContext sets Cancel to + * call the Kill method on the command's Process. + * + * Typically a custom Cancel will send a signal to the command's + * Process, but it may instead take other actions to initiate cancellation, + * such as closing a stdin or stdout pipe or sending a shutdown request on a + * network socket. + * + * If the command exits with a success status after Cancel is + * called, and Cancel does not return an error equivalent to + * os.ErrProcessDone, then Wait and similar methods will return a non-nil + * error: either an error wrapping the one returned by Cancel, + * or the error from the Context. + * (If the command exits with a non-success status, or Cancel + * returns an error that wraps os.ErrProcessDone, Wait and similar methods + * continue to return the command's usual exit status.) + * + * If Cancel is set to nil, nothing will happen immediately when the command's + * Context is done, but a nonzero WaitDelay will still take effect. That may + * be useful, for example, to work around deadlocks in commands that do not + * support shutdown signals but are expected to always finish quickly. + * + * Cancel will not be called if Start returns a non-nil error. + */ + cancel: () => void + /** + * If WaitDelay is non-zero, it bounds the time spent waiting on two sources + * of unexpected delay in Wait: a child process that fails to exit after the + * associated Context is canceled, and a child process that exits but leaves + * its I/O pipes unclosed. + * + * The WaitDelay timer starts when either the associated Context is done or a + * call to Wait observes that the child process has exited, whichever occurs + * first. When the delay has elapsed, the command shuts down the child process + * and/or its I/O pipes. + * + * If the child process has failed to exit — perhaps because it ignored or + * failed to receive a shutdown signal from a Cancel function, or because no + * Cancel function was set — then it will be terminated using os.Process.Kill. + * + * Then, if the I/O pipes communicating with the child process are still open, + * those pipes are closed in order to unblock any goroutines currently blocked + * on Read or Write calls. + * + * If pipes are closed due to WaitDelay, no Cancel call has occurred, + * and the command has otherwise exited with a successful status, Wait and + * similar methods will return ErrWaitDelay instead of nil. + * + * If WaitDelay is zero (the default), I/O pipes will be read until EOF, + * which might not occur until orphaned subprocesses of the command have + * also closed their descriptors for the pipes. + */ + waitDelay: time.Duration + } + interface Cmd { + /** + * String returns a human-readable description of c. + * It is intended only for debugging. + * In particular, it is not suitable for use as input to a shell. + * The output of String may vary across Go releases. + */ + string(): string + } + interface Cmd { + /** + * Run starts the specified command and waits for it to complete. + * + * The returned error is nil if the command runs, has no problems + * copying stdin, stdout, and stderr, and exits with a zero exit + * status. + * + * If the command starts but does not complete successfully, the error is of + * type [*ExitError]. Other error types may be returned for other situations. + * + * If the calling goroutine has locked the operating system thread + * with [runtime.LockOSThread] and modified any inheritable OS-level + * thread state (for example, Linux or Plan 9 name spaces), the new + * process will inherit the caller's thread state. + */ + run(): void + } + interface Cmd { + /** + * Start starts the specified command but does not wait for it to complete. + * + * If Start returns successfully, the c.Process field will be set. + * + * After a successful call to Start the [Cmd.Wait] method must be called in + * order to release associated system resources. + */ + start(): void + } + interface Cmd { + /** + * Wait waits for the command to exit and waits for any copying to + * stdin or copying from stdout or stderr to complete. + * + * The command must have been started by [Cmd.Start]. + * + * The returned error is nil if the command runs, has no problems + * copying stdin, stdout, and stderr, and exits with a zero exit + * status. + * + * If the command fails to run or doesn't complete successfully, the + * error is of type [*ExitError]. Other error types may be + * returned for I/O problems. + * + * If any of c.Stdin, c.Stdout or c.Stderr are not an [*os.File], Wait also waits + * for the respective I/O loop copying to or from the process to complete. + * + * Wait releases any resources associated with the [Cmd]. + */ + wait(): void + } + interface Cmd { + /** + * Output runs the command and returns its standard output. + * Any returned error will usually be of type [*ExitError]. + * If c.Stderr was nil and the returned error is of type + * [*ExitError], Output populates the Stderr field of the + * returned error. + */ + output(): string|Array + } + interface Cmd { + /** + * CombinedOutput runs the command and returns its combined standard + * output and standard error. + */ + combinedOutput(): string|Array + } + interface Cmd { + /** + * StdinPipe returns a pipe that will be connected to the command's + * standard input when the command starts. + * The pipe will be closed automatically after [Cmd.Wait] sees the command exit. + * A caller need only call Close to force the pipe to close sooner. + * For example, if the command being run will not exit until standard input + * is closed, the caller must close the pipe. + */ + stdinPipe(): io.WriteCloser + } + interface Cmd { + /** + * StdoutPipe returns a pipe that will be connected to the command's + * standard output when the command starts. + * + * [Cmd.Wait] will close the pipe after seeing the command exit, so most callers + * need not close the pipe themselves. It is thus incorrect to call Wait + * before all reads from the pipe have completed. + * For the same reason, it is incorrect to call [Cmd.Run] when using StdoutPipe. + * See the example for idiomatic usage. + */ + stdoutPipe(): io.ReadCloser + } + interface Cmd { + /** + * StderrPipe returns a pipe that will be connected to the command's + * standard error when the command starts. + * + * [Cmd.Wait] will close the pipe after seeing the command exit, so most callers + * need not close the pipe themselves. It is thus incorrect to call Wait + * before all reads from the pipe have completed. + * For the same reason, it is incorrect to use [Cmd.Run] when using StderrPipe. + * See the StdoutPipe example for idiomatic usage. + */ + stderrPipe(): io.ReadCloser + } + interface Cmd { + /** + * Environ returns a copy of the environment in which the command would be run + * as it is currently configured. + */ + environ(): Array + } +} + +namespace mailer { + /** + * Message defines a generic email message struct. + */ + interface Message { + from: { address: string; name?: string; } + to: Array<{ address: string; name?: string; }> + bcc: Array<{ address: string; name?: string; }> + cc: Array<{ address: string; name?: string; }> + subject: string + html: string + text: string + headers: _TygojaDict + attachments: _TygojaDict + inlineAttachments: _TygojaDict + } + /** + * Mailer defines a base mail client interface. + */ + interface Mailer { + [key:string]: any; + /** + * Send sends an email with the provided Message. + */ + send(message: Message): void + } +} + +namespace router { + // @ts-ignore + import validation = ozzo_validation + /** + * ApiError defines the struct for a basic api error response. + */ + interface ApiError { + data: _TygojaDict + message: string + status: number + } + interface ApiError { + /** + * Error makes it compatible with the `error` interface. + */ + error(): string + } + interface ApiError { + /** + * RawData returns the unformatted error data (could be an internal error, text, etc.) + */ + rawData(): any + } + interface ApiError { + /** + * Is reports whether the current ApiError wraps the target. + */ + is(target: Error): boolean + } + /** + * Event specifies based Route handler event that is usually intended + * to be embedded as part of a custom event struct. + * + * NB! It is expected that the Response and Request fields are always set. + */ + type _siApGIS = hook.Event + interface Event extends _siApGIS { + response: http.ResponseWriter + request?: http.Request + } + interface Event { + /** + * Written reports whether the current response has already been written. + * + * This method always returns false if e.ResponseWritter doesn't implement the WriteTracker interface + * (all router package handlers receives a ResponseWritter that implements it unless explicitly replaced with a custom one). + */ + written(): boolean + } + interface Event { + /** + * Status reports the status code of the current response. + * + * This method always returns 0 if e.Response doesn't implement the StatusTracker interface + * (all router package handlers receives a ResponseWritter that implements it unless explicitly replaced with a custom one). + */ + status(): number + } + interface Event { + /** + * Flush flushes buffered data to the current response. + * + * Returns [http.ErrNotSupported] if e.Response doesn't implement the [http.Flusher] interface + * (all router package handlers receives a ResponseWritter that implements it unless explicitly replaced with a custom one). + */ + flush(): void + } + interface Event { + /** + * IsTLS reports whether the connection on which the request was received is TLS. + */ + isTLS(): boolean + } + interface Event { + /** + * SetCookie is an alias for [http.SetCookie]. + * + * SetCookie adds a Set-Cookie header to the current response's headers. + * The provided cookie must have a valid Name. + * Invalid cookies may be silently dropped. + */ + setCookie(cookie: http.Cookie): void + } + interface Event { + /** + * RemoteIP returns the IP address of the client that sent the request. + * + * IPv6 addresses are returned expanded. + * For example, "2001:db8::1" becomes "2001:0db8:0000:0000:0000:0000:0000:0001". + * + * Note that if you are behind reverse proxy(ies), this method returns + * the IP of the last connecting proxy. + */ + remoteIP(): string + } + interface Event { + /** + * FindUploadedFiles extracts all form files of "key" from a http request + * and returns a slice with filesystem.File instances (if any). + */ + findUploadedFiles(key: string): Array<(filesystem.File | undefined)> + } + interface Event { + /** + * Get retrieves single value from the current event data store. + */ + get(key: string): any + } + interface Event { + /** + * GetAll returns a copy of the current event data store. + */ + getAll(): _TygojaDict + } + interface Event { + /** + * Set saves single value into the current event data store. + */ + set(key: string, value: any): void + } + interface Event { + /** + * SetAll saves all items from m into the current event data store. + */ + setAll(m: _TygojaDict): void + } + interface Event { + /** + * String writes a plain string response. + */ + string(status: number, data: string): void + } + interface Event { + /** + * HTML writes an HTML response. + */ + html(status: number, data: string): void + } + interface Event { + /** + * JSON writes a JSON response. + * + * It also provides a generic response data fields picker if the "fields" query parameter is set. + * For example, if you are requesting `?fields=a,b` for `e.JSON(200, map[string]int{ "a":1, "b":2, "c":3 })`, + * it should result in a JSON response like: `{"a":1, "b": 2}`. + */ + json(status: number, data: any): void + } + interface Event { + /** + * XML writes an XML response. + * It automatically prepends the generic [xml.Header] string to the response. + */ + xml(status: number, data: any): void + } + interface Event { + /** + * Stream streams the specified reader into the response. + */ + stream(status: number, contentType: string, reader: io.Reader): void + } + interface Event { + /** + * Blob writes a blob (bytes slice) response. + */ + blob(status: number, contentType: string, b: string|Array): void + } + interface Event { + /** + * FileFS serves the specified filename from fsys. + * + * It is similar to [echo.FileFS] for consistency with earlier versions. + */ + fileFS(fsys: fs.FS, filename: string): void + } + interface Event { + /** + * NoContent writes a response with no body (ex. 204). + */ + noContent(status: number): void + } + interface Event { + /** + * Redirect writes a redirect response to the specified url. + * The status code must be in between 300 – 399 range. + */ + redirect(status: number, url: string): void + } + interface Event { + error(status: number, message: string, errData: any): (ApiError) + } + interface Event { + badRequestError(message: string, errData: any): (ApiError) + } + interface Event { + notFoundError(message: string, errData: any): (ApiError) + } + interface Event { + forbiddenError(message: string, errData: any): (ApiError) + } + interface Event { + unauthorizedError(message: string, errData: any): (ApiError) + } + interface Event { + tooManyRequestsError(message: string, errData: any): (ApiError) + } + interface Event { + internalServerError(message: string, errData: any): (ApiError) + } + interface Event { + /** + * BindBody unmarshal the request body into the provided dst. + * + * dst must be either a struct pointer or map[string]any. + * + * The rules how the body will be scanned depends on the request Content-Type. + * + * Currently the following Content-Types are supported: + * ``` + * - application/json + * - text/xml, application/xml + * - multipart/form-data, application/x-www-form-urlencoded + * ``` + * + * Respectively the following struct tags are supported (again, which one will be used depends on the Content-Type): + * ``` + * - "json" (json body)- uses the builtin Go json package for unmarshaling. + * - "xml" (xml body) - uses the builtin Go xml package for unmarshaling. + * - "form" (form data) - utilizes the custom [router.UnmarshalRequestData] method. + * ``` + * + * NB! When dst is a struct make sure that it doesn't have public fields + * that shouldn't be bindable and it is advisible such fields to be unexported + * or have a separate struct just for the binding. For example: + * + * ``` + * data := struct{ + * somethingPrivate string + * + * Title string `json:"title" form:"title"` + * Total int `json:"total" form:"total"` + * } + * err := e.BindBody(&data) + * ``` + */ + bindBody(dst: any): void + } + /** + * Router defines a thin wrapper around the standard Go [http.ServeMux] by + * adding support for routing sub-groups, middlewares and other common utils. + * + * Example: + * + * ``` + * r := NewRouter[*MyEvent](eventFactory) + * + * // middlewares + * r.BindFunc(m1, m2) + * + * // routes + * r.GET("/test", handler1) + * + * // sub-routers/groups + * api := r.Group("/api") + * api.GET("/admins", handler2) + * + * // generate a http.ServeMux instance based on the router configurations + * mux, _ := r.BuildMux() + * + * http.ListenAndServe("localhost:8090", mux) + * ``` + */ + type _spQVinT = RouterGroup + interface Router extends _spQVinT { + } + interface Router { + /** + * BuildMux constructs a new mux [http.Handler] instance from the current router configurations. + */ + buildMux(): http.Handler + } +} + +/** + * Package cron implements a crontab-like service to execute and schedule + * repeative tasks/jobs. * - * Even if this line is disabled, computeExpensiveValue will be called. - * To avoid that, define a type implementing LogValuer: + * Example: * * ``` - * type expensive struct { arg int } - * - * func (e expensive) LogValue() slog.Value { - * return slog.AnyValue(computeExpensiveValue(e.arg)) - * } + * c := cron.New() + * c.MustAdd("dailyReport", "0 0 * * *", func() { ... }) + * c.Start() * ``` + */ +namespace cron { + /** + * Cron is a crontab-like struct for tasks/jobs scheduling. + */ + interface Cron { + } + interface Cron { + /** + * SetInterval changes the current cron tick interval + * (it usually should be >= 1 minute). + */ + setInterval(d: time.Duration): void + } + interface Cron { + /** + * SetTimezone changes the current cron tick timezone. + */ + setTimezone(l: time.Location): void + } + interface Cron { + /** + * MustAdd is similar to Add() but panic on failure. + */ + mustAdd(jobId: string, cronExpr: string, run: () => void): void + } + interface Cron { + /** + * Add registers a single cron job. + * + * If there is already a job with the provided id, then the old job + * will be replaced with the new one. + * + * cronExpr is a regular cron expression, eg. "0 *\/3 * * *" (aka. at minute 0 past every 3rd hour). + * Check cron.NewSchedule() for the supported tokens. + */ + add(jobId: string, cronExpr: string, fn: () => void): void + } + interface Cron { + /** + * Remove removes a single cron job by its id. + */ + remove(jobId: string): void + } + interface Cron { + /** + * RemoveAll removes all registered cron jobs. + */ + removeAll(): void + } + interface Cron { + /** + * Total returns the current total number of registered cron jobs. + */ + total(): number + } + interface Cron { + /** + * Jobs returns a shallow copy of the currently registered cron jobs. + */ + jobs(): Array<(Job | undefined)> + } + interface Cron { + /** + * Stop stops the current cron ticker (if not already). + * + * You can resume the ticker by calling Start(). + */ + stop(): void + } + interface Cron { + /** + * Start starts the cron ticker. + * + * Calling Start() on already started cron will restart the ticker. + */ + start(): void + } + interface Cron { + /** + * HasStarted checks whether the current Cron ticker has been started. + */ + hasStarted(): boolean + } +} + +namespace subscriptions { + /** + * Broker defines a struct for managing subscriptions clients. + */ + interface Broker { + } + interface Broker { + /** + * Clients returns a shallow copy of all registered clients indexed + * with their connection id. + */ + clients(): _TygojaDict + } + interface Broker { + /** + * ChunkedClients splits the current clients into a chunked slice. + */ + chunkedClients(chunkSize: number): Array> + } + interface Broker { + /** + * TotalClients returns the total number of registered clients. + */ + totalClients(): number + } + interface Broker { + /** + * ClientById finds a registered client by its id. + * + * Returns non-nil error when client with clientId is not registered. + */ + clientById(clientId: string): Client + } + interface Broker { + /** + * Register adds a new client to the broker instance. + */ + register(client: Client): void + } + interface Broker { + /** + * Unregister removes a single client by its id and marks it as discarded. + * + * If client with clientId doesn't exist, this method does nothing. + */ + unregister(clientId: string): void + } + /** + * Client is an interface for a generic subscription client. + */ + interface Client { + [key:string]: any; + /** + * Id Returns the unique id of the client. + */ + id(): string + /** + * Channel returns the client's communication channel. + * + * NB! The channel shouldn't be used after calling Discard(). + */ + channel(): undefined + /** + * Subscriptions returns a shallow copy of the client subscriptions matching the prefixes. + * If no prefix is specified, returns all subscriptions. + */ + subscriptions(...prefixes: string[]): _TygojaDict + /** + * Subscribe subscribes the client to the provided subscriptions list. + * + * Each subscription can also have "options" (json serialized SubscriptionOptions) as query parameter. + * + * Example: + * + * ``` + * Subscribe( + * "subscriptionA", + * `subscriptionB?options={"query":{"a":1},"headers":{"x_token":"abc"}}`, + * ) + * ``` + */ + subscribe(...subs: string[]): void + /** + * Unsubscribe unsubscribes the client from the provided subscriptions list. + */ + unsubscribe(...subs: string[]): void + /** + * HasSubscription checks if the client is subscribed to `sub`. + */ + hasSubscription(sub: string): boolean + /** + * Set stores any value to the client's context. + */ + set(key: string, value: any): void + /** + * Unset removes a single value from the client's context. + */ + unset(key: string): void + /** + * Get retrieves the key value from the client's context. + */ + get(key: string): any + /** + * Discard marks the client as "discarded" (and closes its channel), + * meaning that it shouldn't be used anymore for sending new messages. + * + * It is safe to call Discard() multiple times. + */ + discard(): void + /** + * IsDiscarded indicates whether the client has been "discarded" + * and should no longer be used. + */ + isDiscarded(): boolean + /** + * Send sends the specified message to the client's channel (if not discarded). + */ + send(m: Message): void + } + /** + * Message defines a client's channel data. + */ + interface Message { + name: string + data: string|Array + } + interface Message { + /** + * WriteSSE writes the current message in a SSE format into the provided writer. + * + * For example, writing to a router.Event: + * + * ``` + * m := Message{Name: "users/create", Data: []byte{...}} + * m.WriteSSE(e.Response, "yourEventId") + * e.Flush() + * ``` + */ + writeSSE(w: io.Writer, eventId: string): void + } +} + +namespace auth { + /** + * Provider defines a common interface for an OAuth2 client. + */ + interface Provider { + [key:string]: any; + /** + * Context returns the context associated with the provider (if any). + */ + context(): context.Context + /** + * SetContext assigns the specified context to the current provider. + */ + setContext(ctx: context.Context): void + /** + * PKCE indicates whether the provider can use the PKCE flow. + */ + pkce(): boolean + /** + * SetPKCE toggles the state whether the provider can use the PKCE flow or not. + */ + setPKCE(enable: boolean): void + /** + * DisplayName usually returns provider name as it is officially written + * and it could be used directly in the UI. + */ + displayName(): string + /** + * SetDisplayName sets the provider's display name. + */ + setDisplayName(displayName: string): void + /** + * Scopes returns the provider access permissions that will be requested. + */ + scopes(): Array + /** + * SetScopes sets the provider access permissions that will be requested later. + */ + setScopes(scopes: Array): void + /** + * ClientId returns the provider client's app ID. + */ + clientId(): string + /** + * SetClientId sets the provider client's ID. + */ + setClientId(clientId: string): void + /** + * ClientSecret returns the provider client's app secret. + */ + clientSecret(): string + /** + * SetClientSecret sets the provider client's app secret. + */ + setClientSecret(secret: string): void + /** + * RedirectURL returns the end address to redirect the user + * going through the OAuth flow. + */ + redirectURL(): string + /** + * SetRedirectURL sets the provider's RedirectURL. + */ + setRedirectURL(url: string): void + /** + * AuthURL returns the provider's authorization service url. + */ + authURL(): string + /** + * SetAuthURL sets the provider's AuthURL. + */ + setAuthURL(url: string): void + /** + * TokenURL returns the provider's token exchange service url. + */ + tokenURL(): string + /** + * SetTokenURL sets the provider's TokenURL. + */ + setTokenURL(url: string): void + /** + * UserInfoURL returns the provider's user info api url. + */ + userInfoURL(): string + /** + * SetUserInfoURL sets the provider's UserInfoURL. + */ + setUserInfoURL(url: string): void + /** + * Extra returns a shallow copy of any custom config data + * that the provider may be need. + */ + extra(): _TygojaDict + /** + * SetExtra updates the provider's custom config data. + */ + setExtra(data: _TygojaDict): void + /** + * Client returns an http client using the provided token. + */ + client(token: oauth2.Token): (any) + /** + * BuildAuthURL returns a URL to the provider's consent page + * that asks for permissions for the required scopes explicitly. + */ + buildAuthURL(state: string, ...opts: oauth2.AuthCodeOption[]): string + /** + * FetchToken converts an authorization code to token. + */ + fetchToken(code: string, ...opts: oauth2.AuthCodeOption[]): (oauth2.Token) + /** + * FetchRawUserInfo requests and marshalizes into `result` the + * the OAuth user api response. + */ + fetchRawUserInfo(token: oauth2.Token): string|Array + /** + * FetchAuthUser is similar to FetchRawUserInfo, but normalizes and + * marshalizes the user api response into a standardized AuthUser struct. + */ + fetchAuthUser(token: oauth2.Token): (AuthUser) + } + /** + * AuthUser defines a standardized OAuth2 user data structure. + */ + interface AuthUser { + expiry: types.DateTime + rawUser: _TygojaDict + id: string + name: string + username: string + email: string + avatarURL: string + accessToken: string + refreshToken: string + /** + * @todo + * deprecated: use AvatarURL instead + * AvatarUrl will be removed after dropping v0.22 support + */ + avatarUrl: string + } + interface AuthUser { + /** + * MarshalJSON implements the [json.Marshaler] interface. + * + * @todo remove after dropping v0.22 support + */ + marshalJSON(): string|Array + } +} + +/** + * Package cobra is a commander providing a simple interface to create powerful modern CLI interfaces. + * In addition to providing an interface, Cobra simultaneously provides a controller to organize your application code. + */ +namespace cobra { + interface Command { + /** + * GenBashCompletion generates bash completion file and writes to the passed writer. + */ + genBashCompletion(w: io.Writer): void + } + interface Command { + /** + * GenBashCompletionFile generates bash completion file. + */ + genBashCompletionFile(filename: string): void + } + interface Command { + /** + * GenBashCompletionFileV2 generates Bash completion version 2. + */ + genBashCompletionFileV2(filename: string, includeDesc: boolean): void + } + interface Command { + /** + * GenBashCompletionV2 generates Bash completion file version 2 + * and writes it to the passed writer. + */ + genBashCompletionV2(w: io.Writer, includeDesc: boolean): void + } + // @ts-ignore + import flag = pflag + /** + * Command is just that, a command for your application. + * E.g. 'go run ...' - 'run' is the command. Cobra requires + * you to define the usage and description as part of your command + * definition to ensure usability. + */ + interface Command { + /** + * Use is the one-line usage message. + * Recommended syntax is as follows: + * ``` + * [ ] identifies an optional argument. Arguments that are not enclosed in brackets are required. + * ... indicates that you can specify multiple values for the previous argument. + * | indicates mutually exclusive information. You can use the argument to the left of the separator or the + * argument to the right of the separator. You cannot use both arguments in a single use of the command. + * { } delimits a set of mutually exclusive arguments when one of the arguments is required. If the arguments are + * optional, they are enclosed in brackets ([ ]). + * ``` + * Example: add [-F file | -D dir]... [-f format] profile + */ + use: string + /** + * Aliases is an array of aliases that can be used instead of the first word in Use. + */ + aliases: Array + /** + * SuggestFor is an array of command names for which this command will be suggested - + * similar to aliases but only suggests. + */ + suggestFor: Array + /** + * Short is the short description shown in the 'help' output. + */ + short: string + /** + * The group id under which this subcommand is grouped in the 'help' output of its parent. + */ + groupID: string + /** + * Long is the long message shown in the 'help ' output. + */ + long: string + /** + * Example is examples of how to use the command. + */ + example: string + /** + * ValidArgs is list of all valid non-flag arguments that are accepted in shell completions + */ + validArgs: Array + /** + * ValidArgsFunction is an optional function that provides valid non-flag arguments for shell completion. + * It is a dynamic version of using ValidArgs. + * Only one of ValidArgs and ValidArgsFunction can be used for a command. + */ + validArgsFunction: CompletionFunc + /** + * Expected arguments + */ + args: PositionalArgs + /** + * ArgAliases is List of aliases for ValidArgs. + * These are not suggested to the user in the shell completion, + * but accepted if entered manually. + */ + argAliases: Array + /** + * BashCompletionFunction is custom bash functions used by the legacy bash autocompletion generator. + * For portability with other shells, it is recommended to instead use ValidArgsFunction + */ + bashCompletionFunction: string + /** + * Deprecated defines, if this command is deprecated and should print this string when used. + */ + deprecated: string + /** + * Annotations are key/value pairs that can be used by applications to identify or + * group commands or set special options. + */ + annotations: _TygojaDict + /** + * Version defines the version for this command. If this value is non-empty and the command does not + * define a "version" flag, a "version" boolean flag will be added to the command and, if specified, + * will print content of the "Version" variable. A shorthand "v" flag will also be added if the + * command does not define one. + */ + version: string + /** + * The *Run functions are executed in the following order: + * ``` + * * PersistentPreRun() + * * PreRun() + * * Run() + * * PostRun() + * * PersistentPostRun() + * ``` + * All functions get the same args, the arguments after the command name. + * The *PreRun and *PostRun functions will only be executed if the Run function of the current + * command has been declared. + * + * PersistentPreRun: children of this command will inherit and execute. + */ + persistentPreRun: (cmd: Command, args: Array) => void + /** + * PersistentPreRunE: PersistentPreRun but returns an error. + */ + persistentPreRunE: (cmd: Command, args: Array) => void + /** + * PreRun: children of this command will not inherit. + */ + preRun: (cmd: Command, args: Array) => void + /** + * PreRunE: PreRun but returns an error. + */ + preRunE: (cmd: Command, args: Array) => void + /** + * Run: Typically the actual work function. Most commands will only implement this. + */ + run: (cmd: Command, args: Array) => void + /** + * RunE: Run but returns an error. + */ + runE: (cmd: Command, args: Array) => void + /** + * PostRun: run after the Run command. + */ + postRun: (cmd: Command, args: Array) => void + /** + * PostRunE: PostRun but returns an error. + */ + postRunE: (cmd: Command, args: Array) => void + /** + * PersistentPostRun: children of this command will inherit and execute after PostRun. + */ + persistentPostRun: (cmd: Command, args: Array) => void + /** + * PersistentPostRunE: PersistentPostRun but returns an error. + */ + persistentPostRunE: (cmd: Command, args: Array) => void + /** + * FParseErrWhitelist flag parse errors to be ignored + */ + fParseErrWhitelist: FParseErrWhitelist + /** + * CompletionOptions is a set of options to control the handling of shell completion + */ + completionOptions: CompletionOptions + /** + * TraverseChildren parses flags on all parents before executing child command. + */ + traverseChildren: boolean + /** + * Hidden defines, if this command is hidden and should NOT show up in the list of available commands. + */ + hidden: boolean + /** + * SilenceErrors is an option to quiet errors down stream. + */ + silenceErrors: boolean + /** + * SilenceUsage is an option to silence usage when an error occurs. + */ + silenceUsage: boolean + /** + * DisableFlagParsing disables the flag parsing. + * If this is true all flags will be passed to the command as arguments. + */ + disableFlagParsing: boolean + /** + * DisableAutoGenTag defines, if gen tag ("Auto generated by spf13/cobra...") + * will be printed by generating docs for this command. + */ + disableAutoGenTag: boolean + /** + * DisableFlagsInUseLine will disable the addition of [flags] to the usage + * line of a command when printing help or generating docs + */ + disableFlagsInUseLine: boolean + /** + * DisableSuggestions disables the suggestions based on Levenshtein distance + * that go along with 'unknown command' messages. + */ + disableSuggestions: boolean + /** + * SuggestionsMinimumDistance defines minimum levenshtein distance to display suggestions. + * Must be > 0. + */ + suggestionsMinimumDistance: number + } + interface Command { + /** + * Context returns underlying command context. If command was executed + * with ExecuteContext or the context was set with SetContext, the + * previously set context will be returned. Otherwise, nil is returned. + * + * Notice that a call to Execute and ExecuteC will replace a nil context of + * a command with a context.Background, so a background context will be + * returned by Context after one of these functions has been called. + */ + context(): context.Context + } + interface Command { + /** + * SetContext sets context for the command. This context will be overwritten by + * Command.ExecuteContext or Command.ExecuteContextC. + */ + setContext(ctx: context.Context): void + } + interface Command { + /** + * SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden + * particularly useful when testing. + */ + setArgs(a: Array): void + } + interface Command { + /** + * SetOutput sets the destination for usage and error messages. + * If output is nil, os.Stderr is used. + * + * Deprecated: Use SetOut and/or SetErr instead + */ + setOutput(output: io.Writer): void + } + interface Command { + /** + * SetOut sets the destination for usage messages. + * If newOut is nil, os.Stdout is used. + */ + setOut(newOut: io.Writer): void + } + interface Command { + /** + * SetErr sets the destination for error messages. + * If newErr is nil, os.Stderr is used. + */ + setErr(newErr: io.Writer): void + } + interface Command { + /** + * SetIn sets the source for input data + * If newIn is nil, os.Stdin is used. + */ + setIn(newIn: io.Reader): void + } + interface Command { + /** + * SetUsageFunc sets usage function. Usage can be defined by application. + */ + setUsageFunc(f: (_arg0: Command) => void): void + } + interface Command { + /** + * SetUsageTemplate sets usage template. Can be defined by Application. + */ + setUsageTemplate(s: string): void + } + interface Command { + /** + * SetFlagErrorFunc sets a function to generate an error when flag parsing + * fails. + */ + setFlagErrorFunc(f: (_arg0: Command, _arg1: Error) => void): void + } + interface Command { + /** + * SetHelpFunc sets help function. Can be defined by Application. + */ + setHelpFunc(f: (_arg0: Command, _arg1: Array) => void): void + } + interface Command { + /** + * SetHelpCommand sets help command. + */ + setHelpCommand(cmd: Command): void + } + interface Command { + /** + * SetHelpCommandGroupID sets the group id of the help command. + */ + setHelpCommandGroupID(groupID: string): void + } + interface Command { + /** + * SetCompletionCommandGroupID sets the group id of the completion command. + */ + setCompletionCommandGroupID(groupID: string): void + } + interface Command { + /** + * SetHelpTemplate sets help template to be used. Application can use it to set custom template. + */ + setHelpTemplate(s: string): void + } + interface Command { + /** + * SetVersionTemplate sets version template to be used. Application can use it to set custom template. + */ + setVersionTemplate(s: string): void + } + interface Command { + /** + * SetErrPrefix sets error message prefix to be used. Application can use it to set custom prefix. + */ + setErrPrefix(s: string): void + } + interface Command { + /** + * SetGlobalNormalizationFunc sets a normalization function to all flag sets and also to child commands. + * The user should not have a cyclic dependency on commands. + */ + setGlobalNormalizationFunc(n: (f: any, name: string) => any): void + } + interface Command { + /** + * OutOrStdout returns output to stdout. + */ + outOrStdout(): io.Writer + } + interface Command { + /** + * OutOrStderr returns output to stderr + */ + outOrStderr(): io.Writer + } + interface Command { + /** + * ErrOrStderr returns output to stderr + */ + errOrStderr(): io.Writer + } + interface Command { + /** + * InOrStdin returns input to stdin + */ + inOrStdin(): io.Reader + } + interface Command { + /** + * UsageFunc returns either the function set by SetUsageFunc for this command + * or a parent, or it returns a default usage function. + */ + usageFunc(): (_arg0: Command) => void + } + interface Command { + /** + * Usage puts out the usage for the command. + * Used when a user provides invalid input. + * Can be defined by user by overriding UsageFunc. + */ + usage(): void + } + interface Command { + /** + * HelpFunc returns either the function set by SetHelpFunc for this command + * or a parent, or it returns a function with default help behavior. + */ + helpFunc(): (_arg0: Command, _arg1: Array) => void + } + interface Command { + /** + * Help puts out the help for the command. + * Used when a user calls help [command]. + * Can be defined by user by overriding HelpFunc. + */ + help(): void + } + interface Command { + /** + * UsageString returns usage string. + */ + usageString(): string + } + interface Command { + /** + * FlagErrorFunc returns either the function set by SetFlagErrorFunc for this + * command or a parent, or it returns a function which returns the original + * error. + */ + flagErrorFunc(): (_arg0: Command, _arg1: Error) => void + } + interface Command { + /** + * UsagePadding return padding for the usage. + */ + usagePadding(): number + } + interface Command { + /** + * CommandPathPadding return padding for the command path. + */ + commandPathPadding(): number + } + interface Command { + /** + * NamePadding returns padding for the name. + */ + namePadding(): number + } + interface Command { + /** + * UsageTemplate returns usage template for the command. + * This function is kept for backwards-compatibility reasons. + */ + usageTemplate(): string + } + interface Command { + /** + * HelpTemplate return help template for the command. + * This function is kept for backwards-compatibility reasons. + */ + helpTemplate(): string + } + interface Command { + /** + * VersionTemplate return version template for the command. + * This function is kept for backwards-compatibility reasons. + */ + versionTemplate(): string + } + interface Command { + /** + * ErrPrefix return error message prefix for the command + */ + errPrefix(): string + } + interface Command { + /** + * Find the target command given the args and command tree + * Meant to be run on the highest node. Only searches down. + */ + find(args: Array): [(Command), Array] + } + interface Command { + /** + * Traverse the command tree to find the command, and parse args for + * each parent. + */ + traverse(args: Array): [(Command), Array] + } + interface Command { + /** + * SuggestionsFor provides suggestions for the typedName. + */ + suggestionsFor(typedName: string): Array + } + interface Command { + /** + * VisitParents visits all parents of the command and invokes fn on each parent. + */ + visitParents(fn: (_arg0: Command) => void): void + } + interface Command { + /** + * Root finds root command. + */ + root(): (Command) + } + interface Command { + /** + * ArgsLenAtDash will return the length of c.Flags().Args at the moment + * when a -- was found during args parsing. + */ + argsLenAtDash(): number + } + interface Command { + /** + * ExecuteContext is the same as Execute(), but sets the ctx on the command. + * Retrieve ctx by calling cmd.Context() inside your *Run lifecycle or ValidArgs + * functions. + */ + executeContext(ctx: context.Context): void + } + interface Command { + /** + * Execute uses the args (os.Args[1:] by default) + * and run through the command tree finding appropriate matches + * for commands and then corresponding flags. + */ + execute(): void + } + interface Command { + /** + * ExecuteContextC is the same as ExecuteC(), but sets the ctx on the command. + * Retrieve ctx by calling cmd.Context() inside your *Run lifecycle or ValidArgs + * functions. + */ + executeContextC(ctx: context.Context): (Command) + } + interface Command { + /** + * ExecuteC executes the command. + */ + executeC(): (Command) + } + interface Command { + validateArgs(args: Array): void + } + interface Command { + /** + * ValidateRequiredFlags validates all required flags are present and returns an error otherwise + */ + validateRequiredFlags(): void + } + interface Command { + /** + * InitDefaultHelpFlag adds default help flag to c. + * It is called automatically by executing the c or by calling help and usage. + * If c already has help flag, it will do nothing. + */ + initDefaultHelpFlag(): void + } + interface Command { + /** + * InitDefaultVersionFlag adds default version flag to c. + * It is called automatically by executing the c. + * If c already has a version flag, it will do nothing. + * If c.Version is empty, it will do nothing. + */ + initDefaultVersionFlag(): void + } + interface Command { + /** + * InitDefaultHelpCmd adds default help command to c. + * It is called automatically by executing the c or by calling help and usage. + * If c already has help command or c has no subcommands, it will do nothing. + */ + initDefaultHelpCmd(): void + } + interface Command { + /** + * ResetCommands delete parent, subcommand and help command from c. + */ + resetCommands(): void + } + interface Command { + /** + * Commands returns a sorted slice of child commands. + */ + commands(): Array<(Command | undefined)> + } + interface Command { + /** + * AddCommand adds one or more commands to this parent command. + */ + addCommand(...cmds: (Command | undefined)[]): void + } + interface Command { + /** + * Groups returns a slice of child command groups. + */ + groups(): Array<(Group | undefined)> + } + interface Command { + /** + * AllChildCommandsHaveGroup returns if all subcommands are assigned to a group + */ + allChildCommandsHaveGroup(): boolean + } + interface Command { + /** + * ContainsGroup return if groupID exists in the list of command groups. + */ + containsGroup(groupID: string): boolean + } + interface Command { + /** + * AddGroup adds one or more command groups to this parent command. + */ + addGroup(...groups: (Group | undefined)[]): void + } + interface Command { + /** + * RemoveCommand removes one or more commands from a parent command. + */ + removeCommand(...cmds: (Command | undefined)[]): void + } + interface Command { + /** + * Print is a convenience method to Print to the defined output, fallback to Stderr if not set. + */ + print(...i: { + }[]): void + } + interface Command { + /** + * Println is a convenience method to Println to the defined output, fallback to Stderr if not set. + */ + println(...i: { + }[]): void + } + interface Command { + /** + * Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set. + */ + printf(format: string, ...i: { + }[]): void + } + interface Command { + /** + * PrintErr is a convenience method to Print to the defined Err output, fallback to Stderr if not set. + */ + printErr(...i: { + }[]): void + } + interface Command { + /** + * PrintErrln is a convenience method to Println to the defined Err output, fallback to Stderr if not set. + */ + printErrln(...i: { + }[]): void + } + interface Command { + /** + * PrintErrf is a convenience method to Printf to the defined Err output, fallback to Stderr if not set. + */ + printErrf(format: string, ...i: { + }[]): void + } + interface Command { + /** + * CommandPath returns the full path to this command. + */ + commandPath(): string + } + interface Command { + /** + * DisplayName returns the name to display in help text. Returns command Name() + * If CommandDisplayNameAnnoation is not set + */ + displayName(): string + } + interface Command { + /** + * UseLine puts out the full usage for a given command (including parents). + */ + useLine(): string + } + interface Command { + /** + * DebugFlags used to determine which flags have been assigned to which commands + * and which persist. + */ + debugFlags(): void + } + interface Command { + /** + * Name returns the command's name: the first word in the use line. + */ + name(): string + } + interface Command { + /** + * HasAlias determines if a given string is an alias of the command. + */ + hasAlias(s: string): boolean + } + interface Command { + /** + * CalledAs returns the command name or alias that was used to invoke + * this command or an empty string if the command has not been called. + */ + calledAs(): string + } + interface Command { + /** + * NameAndAliases returns a list of the command name and all aliases + */ + nameAndAliases(): string + } + interface Command { + /** + * HasExample determines if the command has example. + */ + hasExample(): boolean + } + interface Command { + /** + * Runnable determines if the command is itself runnable. + */ + runnable(): boolean + } + interface Command { + /** + * HasSubCommands determines if the command has children commands. + */ + hasSubCommands(): boolean + } + interface Command { + /** + * IsAvailableCommand determines if a command is available as a non-help command + * (this includes all non deprecated/hidden commands). + */ + isAvailableCommand(): boolean + } + interface Command { + /** + * IsAdditionalHelpTopicCommand determines if a command is an additional + * help topic command; additional help topic command is determined by the + * fact that it is NOT runnable/hidden/deprecated, and has no sub commands that + * are runnable/hidden/deprecated. + * Concrete example: https://github.com/spf13/cobra/issues/393#issuecomment-282741924. + */ + isAdditionalHelpTopicCommand(): boolean + } + interface Command { + /** + * HasHelpSubCommands determines if a command has any available 'help' sub commands + * that need to be shown in the usage/help default template under 'additional help + * topics'. + */ + hasHelpSubCommands(): boolean + } + interface Command { + /** + * HasAvailableSubCommands determines if a command has available sub commands that + * need to be shown in the usage/help default template under 'available commands'. + */ + hasAvailableSubCommands(): boolean + } + interface Command { + /** + * HasParent determines if the command is a child command. + */ + hasParent(): boolean + } + interface Command { + /** + * GlobalNormalizationFunc returns the global normalization function or nil if it doesn't exist. + */ + globalNormalizationFunc(): (f: any, name: string) => any + } + interface Command { + /** + * Flags returns the complete FlagSet that applies + * to this command (local and persistent declared here and by all parents). + */ + flags(): (any) + } + interface Command { + /** + * LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands. + * This function does not modify the flags of the current command, it's purpose is to return the current state. + */ + localNonPersistentFlags(): (any) + } + interface Command { + /** + * LocalFlags returns the local FlagSet specifically set in the current command. + * This function does not modify the flags of the current command, it's purpose is to return the current state. + */ + localFlags(): (any) + } + interface Command { + /** + * InheritedFlags returns all flags which were inherited from parent commands. + * This function does not modify the flags of the current command, it's purpose is to return the current state. + */ + inheritedFlags(): (any) + } + interface Command { + /** + * NonInheritedFlags returns all flags which were not inherited from parent commands. + * This function does not modify the flags of the current command, it's purpose is to return the current state. + */ + nonInheritedFlags(): (any) + } + interface Command { + /** + * PersistentFlags returns the persistent FlagSet specifically set in the current command. + */ + persistentFlags(): (any) + } + interface Command { + /** + * ResetFlags deletes all flags from command. + */ + resetFlags(): void + } + interface Command { + /** + * HasFlags checks if the command contains any flags (local plus persistent from the entire structure). + */ + hasFlags(): boolean + } + interface Command { + /** + * HasPersistentFlags checks if the command contains persistent flags. + */ + hasPersistentFlags(): boolean + } + interface Command { + /** + * HasLocalFlags checks if the command has flags specifically declared locally. + */ + hasLocalFlags(): boolean + } + interface Command { + /** + * HasInheritedFlags checks if the command has flags inherited from its parent command. + */ + hasInheritedFlags(): boolean + } + interface Command { + /** + * HasAvailableFlags checks if the command contains any flags (local plus persistent from the entire + * structure) which are not hidden or deprecated. + */ + hasAvailableFlags(): boolean + } + interface Command { + /** + * HasAvailablePersistentFlags checks if the command contains persistent flags which are not hidden or deprecated. + */ + hasAvailablePersistentFlags(): boolean + } + interface Command { + /** + * HasAvailableLocalFlags checks if the command has flags specifically declared locally which are not hidden + * or deprecated. + */ + hasAvailableLocalFlags(): boolean + } + interface Command { + /** + * HasAvailableInheritedFlags checks if the command has flags inherited from its parent command which are + * not hidden or deprecated. + */ + hasAvailableInheritedFlags(): boolean + } + interface Command { + /** + * Flag climbs up the command tree looking for matching flag. + */ + flag(name: string): (any) + } + interface Command { + /** + * ParseFlags parses persistent flag tree and local flags. + */ + parseFlags(args: Array): void + } + interface Command { + /** + * Parent returns a commands parent command. + */ + parent(): (Command) + } + interface Command { + /** + * RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag. + * + * You can use pre-defined completion functions such as [FixedCompletions] or [NoFileCompletions], + * or you can define your own. + */ + registerFlagCompletionFunc(flagName: string, f: CompletionFunc): void + } + interface Command { + /** + * GetFlagCompletionFunc returns the completion function for the given flag of the command, if available. + */ + getFlagCompletionFunc(flagName: string): [CompletionFunc, boolean] + } + interface Command { + /** + * InitDefaultCompletionCmd adds a default 'completion' command to c. + * This function will do nothing if any of the following is true: + * 1- the feature has been explicitly disabled by the program, + * 2- c has no subcommands (to avoid creating one), + * 3- c already has a 'completion' command provided by the program. + */ + initDefaultCompletionCmd(...args: string[]): void + } + interface Command { + /** + * GenFishCompletion generates fish completion file and writes to the passed writer. + */ + genFishCompletion(w: io.Writer, includeDesc: boolean): void + } + interface Command { + /** + * GenFishCompletionFile generates fish completion file. + */ + genFishCompletionFile(filename: string, includeDesc: boolean): void + } + interface Command { + /** + * MarkFlagsRequiredTogether marks the given flags with annotations so that Cobra errors + * if the command is invoked with a subset (but not all) of the given flags. + */ + markFlagsRequiredTogether(...flagNames: string[]): void + } + interface Command { + /** + * MarkFlagsOneRequired marks the given flags with annotations so that Cobra errors + * if the command is invoked without at least one flag from the given set of flags. + */ + markFlagsOneRequired(...flagNames: string[]): void + } + interface Command { + /** + * MarkFlagsMutuallyExclusive marks the given flags with annotations so that Cobra errors + * if the command is invoked with more than one flag from the given set of flags. + */ + markFlagsMutuallyExclusive(...flagNames: string[]): void + } + interface Command { + /** + * ValidateFlagGroups validates the mutuallyExclusive/oneRequired/requiredAsGroup logic and returns the + * first error encountered. + */ + validateFlagGroups(): void + } + interface Command { + /** + * GenPowerShellCompletionFile generates powershell completion file without descriptions. + */ + genPowerShellCompletionFile(filename: string): void + } + interface Command { + /** + * GenPowerShellCompletion generates powershell completion file without descriptions + * and writes it to the passed writer. + */ + genPowerShellCompletion(w: io.Writer): void + } + interface Command { + /** + * GenPowerShellCompletionFileWithDesc generates powershell completion file with descriptions. + */ + genPowerShellCompletionFileWithDesc(filename: string): void + } + interface Command { + /** + * GenPowerShellCompletionWithDesc generates powershell completion file with descriptions + * and writes it to the passed writer. + */ + genPowerShellCompletionWithDesc(w: io.Writer): void + } + interface Command { + /** + * MarkFlagRequired instructs the various shell completion implementations to + * prioritize the named flag when performing completion, + * and causes your command to report an error if invoked without the flag. + */ + markFlagRequired(name: string): void + } + interface Command { + /** + * MarkPersistentFlagRequired instructs the various shell completion implementations to + * prioritize the named persistent flag when performing completion, + * and causes your command to report an error if invoked without the flag. + */ + markPersistentFlagRequired(name: string): void + } + interface Command { + /** + * MarkFlagFilename instructs the various shell completion implementations to + * limit completions for the named flag to the specified file extensions. + */ + markFlagFilename(name: string, ...extensions: string[]): void + } + interface Command { + /** + * MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists. + * The bash completion script will call the bash function f for the flag. + * + * This will only work for bash completion. + * It is recommended to instead use c.RegisterFlagCompletionFunc(...) which allows + * to register a Go function which will work across all shells. + */ + markFlagCustom(name: string, f: string): void + } + interface Command { + /** + * MarkPersistentFlagFilename instructs the various shell completion + * implementations to limit completions for the named persistent flag to the + * specified file extensions. + */ + markPersistentFlagFilename(name: string, ...extensions: string[]): void + } + interface Command { + /** + * MarkFlagDirname instructs the various shell completion implementations to + * limit completions for the named flag to directory names. + */ + markFlagDirname(name: string): void + } + interface Command { + /** + * MarkPersistentFlagDirname instructs the various shell completion + * implementations to limit completions for the named persistent flag to + * directory names. + */ + markPersistentFlagDirname(name: string): void + } + interface Command { + /** + * GenZshCompletionFile generates zsh completion file including descriptions. + */ + genZshCompletionFile(filename: string): void + } + interface Command { + /** + * GenZshCompletion generates zsh completion file including descriptions + * and writes it to the passed writer. + */ + genZshCompletion(w: io.Writer): void + } + interface Command { + /** + * GenZshCompletionFileNoDesc generates zsh completion file without descriptions. + */ + genZshCompletionFileNoDesc(filename: string): void + } + interface Command { + /** + * GenZshCompletionNoDesc generates zsh completion file without descriptions + * and writes it to the passed writer. + */ + genZshCompletionNoDesc(w: io.Writer): void + } + interface Command { + /** + * MarkZshCompPositionalArgumentFile only worked for zsh and its behavior was + * not consistent with Bash completion. It has therefore been disabled. + * Instead, when no other completion is specified, file completion is done by + * default for every argument. One can disable file completion on a per-argument + * basis by using ValidArgsFunction and ShellCompDirectiveNoFileComp. + * To achieve file extension filtering, one can use ValidArgsFunction and + * ShellCompDirectiveFilterFileExt. + * + * Deprecated + */ + markZshCompPositionalArgumentFile(argPosition: number, ...patterns: string[]): void + } + interface Command { + /** + * MarkZshCompPositionalArgumentWords only worked for zsh. It has therefore + * been disabled. + * To achieve the same behavior across all shells, one can use + * ValidArgs (for the first argument only) or ValidArgsFunction for + * any argument (can include the first one also). + * + * Deprecated + */ + markZshCompPositionalArgumentWords(argPosition: number, ...words: string[]): void + } +} + +namespace sync { + // @ts-ignore + import isync = sync + /** + * A Locker represents an object that can be locked and unlocked. + */ + interface Locker { + [key:string]: any; + lock(): void + unlock(): void + } +} + +namespace io { + /** + * WriteCloser is the interface that groups the basic Write and Close methods. + */ + interface WriteCloser { + [key:string]: any; + } +} + +namespace bufio { + /** + * Reader implements buffering for an io.Reader object. + * A new Reader is created by calling [NewReader] or [NewReaderSize]; + * alternatively the zero value of a Reader may be used after calling [Reset] + * on it. + */ + interface Reader { + } + interface Reader { + /** + * Size returns the size of the underlying buffer in bytes. + */ + size(): number + } + interface Reader { + /** + * Reset discards any buffered data, resets all state, and switches + * the buffered reader to read from r. + * Calling Reset on the zero value of [Reader] initializes the internal buffer + * to the default size. + * Calling b.Reset(b) (that is, resetting a [Reader] to itself) does nothing. + */ + reset(r: io.Reader): void + } + interface Reader { + /** + * Peek returns the next n bytes without advancing the reader. The bytes stop + * being valid at the next read call. If necessary, Peek will read more bytes + * into the buffer in order to make n bytes available. If Peek returns fewer + * than n bytes, it also returns an error explaining why the read is short. + * The error is [ErrBufferFull] if n is larger than b's buffer size. + * + * Calling Peek prevents a [Reader.UnreadByte] or [Reader.UnreadRune] call from succeeding + * until the next read operation. + */ + peek(n: number): string|Array + } + interface Reader { + /** + * Discard skips the next n bytes, returning the number of bytes discarded. + * + * If Discard skips fewer than n bytes, it also returns an error. + * If 0 <= n <= b.Buffered(), Discard is guaranteed to succeed without + * reading from the underlying io.Reader. + */ + discard(n: number): number + } + interface Reader { + /** + * Read reads data into p. + * It returns the number of bytes read into p. + * The bytes are taken from at most one Read on the underlying [Reader], + * hence n may be less than len(p). + * To read exactly len(p) bytes, use io.ReadFull(b, p). + * If the underlying [Reader] can return a non-zero count with io.EOF, + * then this Read method can do so as well; see the [io.Reader] docs. + */ + read(p: string|Array): number + } + interface Reader { + /** + * ReadByte reads and returns a single byte. + * If no byte is available, returns an error. + */ + readByte(): number + } + interface Reader { + /** + * UnreadByte unreads the last byte. Only the most recently read byte can be unread. + * + * UnreadByte returns an error if the most recent method called on the + * [Reader] was not a read operation. Notably, [Reader.Peek], [Reader.Discard], and [Reader.WriteTo] are not + * considered read operations. + */ + unreadByte(): void + } + interface Reader { + /** + * ReadRune reads a single UTF-8 encoded Unicode character and returns the + * rune and its size in bytes. If the encoded rune is invalid, it consumes one byte + * and returns unicode.ReplacementChar (U+FFFD) with a size of 1. + */ + readRune(): [number, number] + } + interface Reader { + /** + * UnreadRune unreads the last rune. If the most recent method called on + * the [Reader] was not a [Reader.ReadRune], [Reader.UnreadRune] returns an error. (In this + * regard it is stricter than [Reader.UnreadByte], which will unread the last byte + * from any read operation.) + */ + unreadRune(): void + } + interface Reader { + /** + * Buffered returns the number of bytes that can be read from the current buffer. + */ + buffered(): number + } + interface Reader { + /** + * ReadSlice reads until the first occurrence of delim in the input, + * returning a slice pointing at the bytes in the buffer. + * The bytes stop being valid at the next read. + * If ReadSlice encounters an error before finding a delimiter, + * it returns all the data in the buffer and the error itself (often io.EOF). + * ReadSlice fails with error [ErrBufferFull] if the buffer fills without a delim. + * Because the data returned from ReadSlice will be overwritten + * by the next I/O operation, most clients should use + * [Reader.ReadBytes] or ReadString instead. + * ReadSlice returns err != nil if and only if line does not end in delim. + */ + readSlice(delim: number): string|Array + } + interface Reader { + /** + * ReadLine is a low-level line-reading primitive. Most callers should use + * [Reader.ReadBytes]('\n') or [Reader.ReadString]('\n') instead or use a [Scanner]. + * + * ReadLine tries to return a single line, not including the end-of-line bytes. + * If the line was too long for the buffer then isPrefix is set and the + * beginning of the line is returned. The rest of the line will be returned + * from future calls. isPrefix will be false when returning the last fragment + * of the line. The returned buffer is only valid until the next call to + * ReadLine. ReadLine either returns a non-nil line or it returns an error, + * never both. + * + * The text returned from ReadLine does not include the line end ("\r\n" or "\n"). + * No indication or error is given if the input ends without a final line end. + * Calling [Reader.UnreadByte] after ReadLine will always unread the last byte read + * (possibly a character belonging to the line end) even if that byte is not + * part of the line returned by ReadLine. + */ + readLine(): [string|Array, boolean] + } + interface Reader { + /** + * ReadBytes reads until the first occurrence of delim in the input, + * returning a slice containing the data up to and including the delimiter. + * If ReadBytes encounters an error before finding a delimiter, + * it returns the data read before the error and the error itself (often io.EOF). + * ReadBytes returns err != nil if and only if the returned data does not end in + * delim. + * For simple uses, a Scanner may be more convenient. + */ + readBytes(delim: number): string|Array + } + interface Reader { + /** + * ReadString reads until the first occurrence of delim in the input, + * returning a string containing the data up to and including the delimiter. + * If ReadString encounters an error before finding a delimiter, + * it returns the data read before the error and the error itself (often io.EOF). + * ReadString returns err != nil if and only if the returned data does not end in + * delim. + * For simple uses, a Scanner may be more convenient. + */ + readString(delim: number): string + } + interface Reader { + /** + * WriteTo implements io.WriterTo. + * This may make multiple calls to the [Reader.Read] method of the underlying [Reader]. + * If the underlying reader supports the [Reader.WriteTo] method, + * this calls the underlying [Reader.WriteTo] without buffering. + */ + writeTo(w: io.Writer): number + } + /** + * Writer implements buffering for an [io.Writer] object. + * If an error occurs writing to a [Writer], no more data will be + * accepted and all subsequent writes, and [Writer.Flush], will return the error. + * After all data has been written, the client should call the + * [Writer.Flush] method to guarantee all data has been forwarded to + * the underlying [io.Writer]. + */ + interface Writer { + } + interface Writer { + /** + * Size returns the size of the underlying buffer in bytes. + */ + size(): number + } + interface Writer { + /** + * Reset discards any unflushed buffered data, clears any error, and + * resets b to write its output to w. + * Calling Reset on the zero value of [Writer] initializes the internal buffer + * to the default size. + * Calling w.Reset(w) (that is, resetting a [Writer] to itself) does nothing. + */ + reset(w: io.Writer): void + } + interface Writer { + /** + * Flush writes any buffered data to the underlying [io.Writer]. + */ + flush(): void + } + interface Writer { + /** + * Available returns how many bytes are unused in the buffer. + */ + available(): number + } + interface Writer { + /** + * AvailableBuffer returns an empty buffer with b.Available() capacity. + * This buffer is intended to be appended to and + * passed to an immediately succeeding [Writer.Write] call. + * The buffer is only valid until the next write operation on b. + */ + availableBuffer(): string|Array + } + interface Writer { + /** + * Buffered returns the number of bytes that have been written into the current buffer. + */ + buffered(): number + } + interface Writer { + /** + * Write writes the contents of p into the buffer. + * It returns the number of bytes written. + * If nn < len(p), it also returns an error explaining + * why the write is short. + */ + write(p: string|Array): number + } + interface Writer { + /** + * WriteByte writes a single byte. + */ + writeByte(c: number): void + } + interface Writer { + /** + * WriteRune writes a single Unicode code point, returning + * the number of bytes written and any error. + */ + writeRune(r: number): number + } + interface Writer { + /** + * WriteString writes a string. + * It returns the number of bytes written. + * If the count is less than len(s), it also returns an error explaining + * why the write is short. + */ + writeString(s: string): number + } + interface Writer { + /** + * ReadFrom implements [io.ReaderFrom]. If the underlying writer + * supports the ReadFrom method, this calls the underlying ReadFrom. + * If there is buffered data and an underlying ReadFrom, this fills + * the buffer and writes it before calling ReadFrom. + */ + readFrom(r: io.Reader): number + } +} + +namespace syscall { + // @ts-ignore + import errpkg = errors + /** + * SysProcIDMap holds Container ID to Host ID mappings used for User Namespaces in Linux. + * See user_namespaces(7). + * + * Note that User Namespaces are not available on a number of popular Linux + * versions (due to security issues), or are available but subject to AppArmor + * restrictions like in Ubuntu 24.04. + */ + interface SysProcIDMap { + containerID: number // Container ID. + hostID: number // Host ID. + size: number // Size. + } + // @ts-ignore + import errorspkg = errors + /** + * Credential holds user and group identities to be assumed + * by a child process started by [StartProcess]. + */ + interface Credential { + uid: number // User ID. + gid: number // Group ID. + groups: Array // Supplementary group IDs. + noSetGroups: boolean // If true, don't set supplementary groups + } + // @ts-ignore + import runtimesyscall = syscall + /** + * A Signal is a number describing a process signal. + * It implements the [os.Signal] interface. + */ + interface Signal extends Number{} + interface Signal { + signal(): void + } + interface Signal { + string(): string + } +} + +namespace time { + /** + * A Month specifies a month of the year (January = 1, ...). + */ + interface Month extends Number{} + interface Month { + /** + * String returns the English name of the month ("January", "February", ...). + */ + string(): string + } + /** + * A Weekday specifies a day of the week (Sunday = 0, ...). + */ + interface Weekday extends Number{} + interface Weekday { + /** + * String returns the English name of the day ("Sunday", "Monday", ...). + */ + string(): string + } + /** + * A Location maps time instants to the zone in use at that time. + * Typically, the Location represents the collection of time offsets + * in use in a geographical area. For many Locations the time offset varies + * depending on whether daylight savings time is in use at the time instant. + * + * Location is used to provide a time zone in a printed Time value and for + * calculations involving intervals that may cross daylight savings time + * boundaries. + */ + interface Location { + } + interface Location { + /** + * String returns a descriptive name for the time zone information, + * corresponding to the name argument to [LoadLocation] or [FixedZone]. + */ + string(): string + } +} + +namespace context { +} + +namespace fs { +} + +namespace sql { + /** + * IsolationLevel is the transaction isolation level used in [TxOptions]. + */ + interface IsolationLevel extends Number{} + interface IsolationLevel { + /** + * String returns the name of the transaction isolation level. + */ + string(): string + } + /** + * DBStats contains database statistics. + */ + interface DBStats { + maxOpenConnections: number // Maximum number of open connections to the database. + /** + * Pool Status + */ + openConnections: number // The number of established connections both in use and idle. + inUse: number // The number of connections currently in use. + idle: number // The number of idle connections. + /** + * Counters + */ + waitCount: number // The total number of connections waited for. + waitDuration: time.Duration // The total time blocked waiting for a new connection. + maxIdleClosed: number // The total number of connections closed due to SetMaxIdleConns. + maxIdleTimeClosed: number // The total number of connections closed due to SetConnMaxIdleTime. + maxLifetimeClosed: number // The total number of connections closed due to SetConnMaxLifetime. + } + /** + * Conn represents a single database connection rather than a pool of database + * connections. Prefer running queries from [DB] unless there is a specific + * need for a continuous single database connection. + * + * A Conn must call [Conn.Close] to return the connection to the database pool + * and may do so concurrently with a running query. + * + * After a call to [Conn.Close], all operations on the + * connection fail with [ErrConnDone]. + */ + interface Conn { + } + interface Conn { + /** + * PingContext verifies the connection to the database is still alive. + */ + pingContext(ctx: context.Context): void + } + interface Conn { + /** + * ExecContext executes a query without returning any rows. + * The args are for any placeholder parameters in the query. + */ + execContext(ctx: context.Context, query: string, ...args: any[]): Result + } + interface Conn { + /** + * QueryContext executes a query that returns rows, typically a SELECT. + * The args are for any placeholder parameters in the query. + */ + queryContext(ctx: context.Context, query: string, ...args: any[]): (Rows) + } + interface Conn { + /** + * QueryRowContext executes a query that is expected to return at most one row. + * QueryRowContext always returns a non-nil value. Errors are deferred until + * the [*Row.Scan] method is called. + * If the query selects no rows, the [*Row.Scan] will return [ErrNoRows]. + * Otherwise, the [*Row.Scan] scans the first selected row and discards + * the rest. + */ + queryRowContext(ctx: context.Context, query: string, ...args: any[]): (Row) + } + interface Conn { + /** + * PrepareContext creates a prepared statement for later queries or executions. + * Multiple queries or executions may be run concurrently from the + * returned statement. + * The caller must call the statement's [*Stmt.Close] method + * when the statement is no longer needed. + * + * The provided context is used for the preparation of the statement, not for the + * execution of the statement. + */ + prepareContext(ctx: context.Context, query: string): (Stmt) + } + interface Conn { + /** + * Raw executes f exposing the underlying driver connection for the + * duration of f. The driverConn must not be used outside of f. + * + * Once f returns and err is not [driver.ErrBadConn], the [Conn] will continue to be usable + * until [Conn.Close] is called. + */ + raw(f: (driverConn: any) => void): void + } + interface Conn { + /** + * BeginTx starts a transaction. + * + * The provided context is used until the transaction is committed or rolled back. + * If the context is canceled, the sql package will roll back + * the transaction. [Tx.Commit] will return an error if the context provided to + * BeginTx is canceled. + * + * The provided [TxOptions] is optional and may be nil if defaults should be used. + * If a non-default isolation level is used that the driver doesn't support, + * an error will be returned. + */ + beginTx(ctx: context.Context, opts: TxOptions): (Tx) + } + interface Conn { + /** + * Close returns the connection to the connection pool. + * All operations after a Close will return with [ErrConnDone]. + * Close is safe to call concurrently with other operations and will + * block until all other operations finish. It may be useful to first + * cancel any used context and then call close directly after. + */ + close(): void + } + /** + * ColumnType contains the name and type of a column. + */ + interface ColumnType { + } + interface ColumnType { + /** + * Name returns the name or alias of the column. + */ + name(): string + } + interface ColumnType { + /** + * Length returns the column type length for variable length column types such + * as text and binary field types. If the type length is unbounded the value will + * be [math.MaxInt64] (any database limits will still apply). + * If the column type is not variable length, such as an int, or if not supported + * by the driver ok is false. + */ + length(): [number, boolean] + } + interface ColumnType { + /** + * DecimalSize returns the scale and precision of a decimal type. + * If not applicable or if not supported ok is false. + */ + decimalSize(): [number, number, boolean] + } + interface ColumnType { + /** + * ScanType returns a Go type suitable for scanning into using [Rows.Scan]. + * If a driver does not support this property ScanType will return + * the type of an empty interface. + */ + scanType(): any + } + interface ColumnType { + /** + * Nullable reports whether the column may be null. + * If a driver does not support this property ok will be false. + */ + nullable(): [boolean, boolean] + } + interface ColumnType { + /** + * DatabaseTypeName returns the database system name of the column type. If an empty + * string is returned, then the driver type name is not supported. + * Consult your driver documentation for a list of driver data types. [ColumnType.Length] specifiers + * are not included. + * Common type names include "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL", + * "INT", and "BIGINT". + */ + databaseTypeName(): string + } + /** + * Row is the result of calling [DB.QueryRow] to select a single row. + */ + interface Row { + } + interface Row { + /** + * Scan copies the columns from the matched row into the values + * pointed at by dest. See the documentation on [Rows.Scan] for details. + * If more than one row matches the query, + * Scan uses the first row and discards the rest. If no row matches + * the query, Scan returns [ErrNoRows]. + */ + scan(...dest: any[]): void + } + interface Row { + /** + * Err provides a way for wrapping packages to check for + * query errors without calling [Row.Scan]. + * Err returns the error, if any, that was encountered while running the query. + * If this error is not nil, this error will also be returned from [Row.Scan]. + */ + err(): void + } +} + +/** + * Package url parses URLs and implements query escaping. + */ +namespace url { + /** + * A URL represents a parsed URL (technically, a URI reference). + * + * The general form represented is: + * + * ``` + * [scheme:][//[userinfo@]host][/]path[?query][#fragment] + * ``` + * + * URLs that do not start with a slash after the scheme are interpreted as: + * + * ``` + * scheme:opaque[?query][#fragment] + * ``` + * + * The Host field contains the host and port subcomponents of the URL. + * When the port is present, it is separated from the host with a colon. + * When the host is an IPv6 address, it must be enclosed in square brackets: + * "[fe80::1]:80". The [net.JoinHostPort] function combines a host and port + * into a string suitable for the Host field, adding square brackets to + * the host when necessary. + * + * Note that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/. + * A consequence is that it is impossible to tell which slashes in the Path were + * slashes in the raw URL and which were %2f. This distinction is rarely important, + * but when it is, the code should use the [URL.EscapedPath] method, which preserves + * the original encoding of Path. + * + * The RawPath field is an optional field which is only set when the default + * encoding of Path is different from the escaped path. See the EscapedPath method + * for more details. + * + * URL's String method uses the EscapedPath method to obtain the path. + */ + interface URL { + scheme: string + opaque: string // encoded opaque data + user?: Userinfo // username and password information + host: string // host or host:port (see Hostname and Port methods) + path: string // path (relative paths may omit leading slash) + rawPath: string // encoded path hint (see EscapedPath method) + omitHost: boolean // do not emit empty host (authority) + forceQuery: boolean // append a query ('?') even if RawQuery is empty + rawQuery: string // encoded query values, without '?' + fragment: string // fragment for references, without '#' + rawFragment: string // encoded fragment hint (see EscapedFragment method) + } + interface URL { + /** + * EscapedPath returns the escaped form of u.Path. + * In general there are multiple possible escaped forms of any path. + * EscapedPath returns u.RawPath when it is a valid escaping of u.Path. + * Otherwise EscapedPath ignores u.RawPath and computes an escaped + * form on its own. + * The [URL.String] and [URL.RequestURI] methods use EscapedPath to construct + * their results. + * In general, code should call EscapedPath instead of + * reading u.RawPath directly. + */ + escapedPath(): string + } + interface URL { + /** + * EscapedFragment returns the escaped form of u.Fragment. + * In general there are multiple possible escaped forms of any fragment. + * EscapedFragment returns u.RawFragment when it is a valid escaping of u.Fragment. + * Otherwise EscapedFragment ignores u.RawFragment and computes an escaped + * form on its own. + * The [URL.String] method uses EscapedFragment to construct its result. + * In general, code should call EscapedFragment instead of + * reading u.RawFragment directly. + */ + escapedFragment(): string + } + interface URL { + /** + * String reassembles the [URL] into a valid URL string. + * The general form of the result is one of: + * + * ``` + * scheme:opaque?query#fragment + * scheme://userinfo@host/path?query#fragment + * ``` + * + * If u.Opaque is non-empty, String uses the first form; + * otherwise it uses the second form. + * Any non-ASCII characters in host are escaped. + * To obtain the path, String uses u.EscapedPath(). + * + * In the second form, the following rules apply: + * ``` + * - if u.Scheme is empty, scheme: is omitted. + * - if u.User is nil, userinfo@ is omitted. + * - if u.Host is empty, host/ is omitted. + * - if u.Scheme and u.Host are empty and u.User is nil, + * the entire scheme://userinfo@host/ is omitted. + * - if u.Host is non-empty and u.Path begins with a /, + * the form host/path does not add its own /. + * - if u.RawQuery is empty, ?query is omitted. + * - if u.Fragment is empty, #fragment is omitted. + * ``` + */ + string(): string + } + interface URL { + /** + * Redacted is like [URL.String] but replaces any password with "xxxxx". + * Only the password in u.User is redacted. + */ + redacted(): string + } + /** + * Values maps a string key to a list of values. + * It is typically used for query parameters and form values. + * Unlike in the http.Header map, the keys in a Values map + * are case-sensitive. + */ + interface Values extends _TygojaDict{} + interface Values { + /** + * Get gets the first value associated with the given key. + * If there are no values associated with the key, Get returns + * the empty string. To access multiple values, use the map + * directly. + */ + get(key: string): string + } + interface Values { + /** + * Set sets the key to value. It replaces any existing + * values. + */ + set(key: string, value: string): void + } + interface Values { + /** + * Add adds the value to key. It appends to any existing + * values associated with key. + */ + add(key: string, value: string): void + } + interface Values { + /** + * Del deletes the values associated with key. + */ + del(key: string): void + } + interface Values { + /** + * Has checks whether a given key is set. + */ + has(key: string): boolean + } + interface Values { + /** + * Encode encodes the values into “URL encoded” form + * ("bar=baz&foo=quux") sorted by key. + */ + encode(): string + } + interface URL { + /** + * IsAbs reports whether the [URL] is absolute. + * Absolute means that it has a non-empty scheme. + */ + isAbs(): boolean + } + interface URL { + /** + * Parse parses a [URL] in the context of the receiver. The provided URL + * may be relative or absolute. Parse returns nil, err on parse + * failure, otherwise its return value is the same as [URL.ResolveReference]. + */ + parse(ref: string): (URL) + } + interface URL { + /** + * ResolveReference resolves a URI reference to an absolute URI from + * an absolute base URI u, per RFC 3986 Section 5.2. The URI reference + * may be relative or absolute. ResolveReference always returns a new + * [URL] instance, even if the returned URL is identical to either the + * base or reference. If ref is an absolute URL, then ResolveReference + * ignores base and returns a copy of ref. + */ + resolveReference(ref: URL): (URL) + } + interface URL { + /** + * Query parses RawQuery and returns the corresponding values. + * It silently discards malformed value pairs. + * To check errors use [ParseQuery]. + */ + query(): Values + } + interface URL { + /** + * RequestURI returns the encoded path?query or opaque?query + * string that would be used in an HTTP request for u. + */ + requestURI(): string + } + interface URL { + /** + * Hostname returns u.Host, stripping any valid port number if present. + * + * If the result is enclosed in square brackets, as literal IPv6 addresses are, + * the square brackets are removed from the result. + */ + hostname(): string + } + interface URL { + /** + * Port returns the port part of u.Host, without the leading colon. + * + * If u.Host doesn't contain a valid numeric port, Port returns an empty string. + */ + port(): string + } + interface URL { + marshalBinary(): string|Array + } + interface URL { + appendBinary(b: string|Array): string|Array + } + interface URL { + unmarshalBinary(text: string|Array): void + } + interface URL { + /** + * JoinPath returns a new [URL] with the provided path elements joined to + * any existing path and the resulting path cleaned of any ./ or ../ elements. + * Any sequences of multiple / characters will be reduced to a single /. + */ + joinPath(...elem: string[]): (URL) + } +} + +namespace net { + /** + * Addr represents a network end point address. + * + * The two methods [Addr.Network] and [Addr.String] conventionally return strings + * that can be passed as the arguments to [Dial], but the exact form + * and meaning of the strings is up to the implementation. + */ + interface Addr { + [key:string]: any; + network(): string // name of the network (for example, "tcp", "udp") + string(): string // string form of address (for example, "192.0.2.1:25", "[2001:db8::1]:80") + } +} + +/** + * Package textproto implements generic support for text-based request/response + * protocols in the style of HTTP, NNTP, and SMTP. * - * Then use a value of that type in log calls: + * The package provides: * - * ``` - * slog.Debug("frobbing", "value", expensive{arg}) - * ``` + * [Error], which represents a numeric error response from + * a server. * - * Now computeExpensiveValue will only be called when the line is enabled. + * [Pipeline], to manage pipelined requests and responses + * in a client. * - * The built-in handlers acquire a lock before calling [io.Writer.Write] - * to ensure that exactly one [Record] is written at a time in its entirety. - * Although each log record has a timestamp, - * the built-in handlers do not use that time to sort the written records. - * User-defined handlers are responsible for their own locking and sorting. + * [Reader], to read numeric response code lines, + * key: value headers, lines wrapped with leading spaces + * on continuation lines, and whole text blocks ending + * with a dot on a line by itself. * - * # Writing a handler + * [Writer], to write dot-encoded text blocks. * - * For a guide to writing a custom handler, see https://golang.org/s/slog-handler-guide. + * [Conn], a convenient packaging of [Reader], [Writer], and [Pipeline] for use + * with a single network connection. + */ +namespace textproto { + /** + * A MIMEHeader represents a MIME-style header mapping + * keys to sets of values. + */ + interface MIMEHeader extends _TygojaDict{} + interface MIMEHeader { + /** + * Add adds the key, value pair to the header. + * It appends to any existing values associated with key. + */ + add(key: string, value: string): void + } + interface MIMEHeader { + /** + * Set sets the header entries associated with key to + * the single element value. It replaces any existing + * values associated with key. + */ + set(key: string, value: string): void + } + interface MIMEHeader { + /** + * Get gets the first value associated with the given key. + * It is case insensitive; [CanonicalMIMEHeaderKey] is used + * to canonicalize the provided key. + * If there are no values associated with the key, Get returns "". + * To use non-canonical keys, access the map directly. + */ + get(key: string): string + } + interface MIMEHeader { + /** + * Values returns all values associated with the given key. + * It is case insensitive; [CanonicalMIMEHeaderKey] is + * used to canonicalize the provided key. To use non-canonical + * keys, access the map directly. + * The returned slice is not a copy. + */ + values(key: string): Array + } + interface MIMEHeader { + /** + * Del deletes the values associated with key. + */ + del(key: string): void + } +} + +namespace multipart { + interface Reader { + /** + * ReadForm parses an entire multipart message whose parts have + * a Content-Disposition of "form-data". + * It stores up to maxMemory bytes + 10MB (reserved for non-file parts) + * in memory. File parts which can't be stored in memory will be stored on + * disk in temporary files. + * It returns [ErrMessageTooLarge] if all non-file parts can't be stored in + * memory. + */ + readForm(maxMemory: number): (Form) + } + /** + * Form is a parsed multipart form. + * Its File parts are stored either in memory or on disk, + * and are accessible via the [*FileHeader]'s Open method. + * Its Value parts are stored as strings. + * Both are keyed by field name. + */ + interface Form { + value: _TygojaDict + file: _TygojaDict + } + interface Form { + /** + * RemoveAll removes any temporary files associated with a [Form]. + */ + removeAll(): void + } + /** + * File is an interface to access the file part of a multipart message. + * Its contents may be either stored in memory or on disk. + * If stored on disk, the File's underlying concrete type will be an *os.File. + */ + interface File { + [key:string]: any; + } + /** + * Reader is an iterator over parts in a MIME multipart body. + * Reader's underlying parser consumes its input as needed. Seeking + * isn't supported. + */ + interface Reader { + } + interface Reader { + /** + * NextPart returns the next part in the multipart or an error. + * When there are no more parts, the error [io.EOF] is returned. + * + * As a special case, if the "Content-Transfer-Encoding" header + * has a value of "quoted-printable", that header is instead + * hidden and the body is transparently decoded during Read calls. + */ + nextPart(): (Part) + } + interface Reader { + /** + * NextRawPart returns the next part in the multipart or an error. + * When there are no more parts, the error [io.EOF] is returned. + * + * Unlike [Reader.NextPart], it does not have special handling for + * "Content-Transfer-Encoding: quoted-printable". + */ + nextRawPart(): (Part) + } +} + +namespace http { + /** + * A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an + * HTTP response or the Cookie header of an HTTP request. + * + * See https://tools.ietf.org/html/rfc6265 for details. + */ + interface Cookie { + name: string + value: string + quoted: boolean // indicates whether the Value was originally quoted + path: string // optional + domain: string // optional + expires: time.Time // optional + rawExpires: string // for reading cookies only + /** + * MaxAge=0 means no 'Max-Age' attribute specified. + * MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' + * MaxAge>0 means Max-Age attribute present and given in seconds + */ + maxAge: number + secure: boolean + httpOnly: boolean + sameSite: SameSite + partitioned: boolean + raw: string + unparsed: Array // Raw text of unparsed attribute-value pairs + } + interface Cookie { + /** + * String returns the serialization of the cookie for use in a [Cookie] + * header (if only Name and Value are set) or a Set-Cookie response + * header (if other fields are set). + * If c is nil or c.Name is invalid, the empty string is returned. + */ + string(): string + } + interface Cookie { + /** + * Valid reports whether the cookie is valid. + */ + valid(): void + } + // @ts-ignore + import mathrand = rand + /** + * A Header represents the key-value pairs in an HTTP header. + * + * The keys should be in canonical form, as returned by + * [CanonicalHeaderKey]. + */ + interface Header extends _TygojaDict{} + interface Header { + /** + * Add adds the key, value pair to the header. + * It appends to any existing values associated with key. + * The key is case insensitive; it is canonicalized by + * [CanonicalHeaderKey]. + */ + add(key: string, value: string): void + } + interface Header { + /** + * Set sets the header entries associated with key to the + * single element value. It replaces any existing values + * associated with key. The key is case insensitive; it is + * canonicalized by [textproto.CanonicalMIMEHeaderKey]. + * To use non-canonical keys, assign to the map directly. + */ + set(key: string, value: string): void + } + interface Header { + /** + * Get gets the first value associated with the given key. If + * there are no values associated with the key, Get returns "". + * It is case insensitive; [textproto.CanonicalMIMEHeaderKey] is + * used to canonicalize the provided key. Get assumes that all + * keys are stored in canonical form. To use non-canonical keys, + * access the map directly. + */ + get(key: string): string + } + interface Header { + /** + * Values returns all values associated with the given key. + * It is case insensitive; [textproto.CanonicalMIMEHeaderKey] is + * used to canonicalize the provided key. To use non-canonical + * keys, access the map directly. + * The returned slice is not a copy. + */ + values(key: string): Array + } + interface Header { + /** + * Del deletes the values associated with key. + * The key is case insensitive; it is canonicalized by + * [CanonicalHeaderKey]. + */ + del(key: string): void + } + interface Header { + /** + * Write writes a header in wire format. + */ + write(w: io.Writer): void + } + interface Header { + /** + * Clone returns a copy of h or nil if h is nil. + */ + clone(): Header + } + interface Header { + /** + * WriteSubset writes a header in wire format. + * If exclude is not nil, keys where exclude[key] == true are not written. + * Keys are not canonicalized before checking the exclude map. + */ + writeSubset(w: io.Writer, exclude: _TygojaDict): void + } + /** + * Protocols is a set of HTTP protocols. + * The zero value is an empty set of protocols. + * + * The supported protocols are: + * + * ``` + * - HTTP1 is the HTTP/1.0 and HTTP/1.1 protocols. + * HTTP1 is supported on both unsecured TCP and secured TLS connections. + * + * - HTTP2 is the HTTP/2 protcol over a TLS connection. + * + * - UnencryptedHTTP2 is the HTTP/2 protocol over an unsecured TCP connection. + * ``` + */ + interface Protocols { + } + interface Protocols { + /** + * HTTP1 reports whether p includes HTTP/1. + */ + http1(): boolean + } + interface Protocols { + /** + * SetHTTP1 adds or removes HTTP/1 from p. + */ + setHTTP1(ok: boolean): void + } + interface Protocols { + /** + * HTTP2 reports whether p includes HTTP/2. + */ + http2(): boolean + } + interface Protocols { + /** + * SetHTTP2 adds or removes HTTP/2 from p. + */ + setHTTP2(ok: boolean): void + } + interface Protocols { + /** + * UnencryptedHTTP2 reports whether p includes unencrypted HTTP/2. + */ + unencryptedHTTP2(): boolean + } + interface Protocols { + /** + * SetUnencryptedHTTP2 adds or removes unencrypted HTTP/2 from p. + */ + setUnencryptedHTTP2(ok: boolean): void + } + interface Protocols { + string(): string + } + /** + * HTTP2Config defines HTTP/2 configuration parameters common to + * both [Transport] and [Server]. + */ + interface HTTP2Config { + /** + * MaxConcurrentStreams optionally specifies the number of + * concurrent streams that a peer may have open at a time. + * If zero, MaxConcurrentStreams defaults to at least 100. + */ + maxConcurrentStreams: number + /** + * MaxDecoderHeaderTableSize optionally specifies an upper limit for the + * size of the header compression table used for decoding headers sent + * by the peer. + * A valid value is less than 4MiB. + * If zero or invalid, a default value is used. + */ + maxDecoderHeaderTableSize: number + /** + * MaxEncoderHeaderTableSize optionally specifies an upper limit for the + * header compression table used for sending headers to the peer. + * A valid value is less than 4MiB. + * If zero or invalid, a default value is used. + */ + maxEncoderHeaderTableSize: number + /** + * MaxReadFrameSize optionally specifies the largest frame + * this endpoint is willing to read. + * A valid value is between 16KiB and 16MiB, inclusive. + * If zero or invalid, a default value is used. + */ + maxReadFrameSize: number + /** + * MaxReceiveBufferPerConnection is the maximum size of the + * flow control window for data received on a connection. + * A valid value is at least 64KiB and less than 4MiB. + * If invalid, a default value is used. + */ + maxReceiveBufferPerConnection: number + /** + * MaxReceiveBufferPerStream is the maximum size of + * the flow control window for data received on a stream (request). + * A valid value is less than 4MiB. + * If zero or invalid, a default value is used. + */ + maxReceiveBufferPerStream: number + /** + * SendPingTimeout is the timeout after which a health check using a ping + * frame will be carried out if no frame is received on a connection. + * If zero, no health check is performed. + */ + sendPingTimeout: time.Duration + /** + * PingTimeout is the timeout after which a connection will be closed + * if a response to a ping is not received. + * If zero, a default of 15 seconds is used. + */ + pingTimeout: time.Duration + /** + * WriteByteTimeout is the timeout after which a connection will be + * closed if no data can be written to it. The timeout begins when data is + * available to write, and is extended whenever any bytes are written. + */ + writeByteTimeout: time.Duration + /** + * PermitProhibitedCipherSuites, if true, permits the use of + * cipher suites prohibited by the HTTP/2 spec. + */ + permitProhibitedCipherSuites: boolean + /** + * CountError, if non-nil, is called on HTTP/2 errors. + * It is intended to increment a metric for monitoring. + * The errType contains only lowercase letters, digits, and underscores + * (a-z, 0-9, _). + */ + countError: (errType: string) => void + } + // @ts-ignore + import urlpkg = url + /** + * Response represents the response from an HTTP request. + * + * The [Client] and [Transport] return Responses from servers once + * the response headers have been received. The response body + * is streamed on demand as the Body field is read. + */ + interface Response { + status: string // e.g. "200 OK" + statusCode: number // e.g. 200 + proto: string // e.g. "HTTP/1.0" + protoMajor: number // e.g. 1 + protoMinor: number // e.g. 0 + /** + * Header maps header keys to values. If the response had multiple + * headers with the same key, they may be concatenated, with comma + * delimiters. (RFC 7230, section 3.2.2 requires that multiple headers + * be semantically equivalent to a comma-delimited sequence.) When + * Header values are duplicated by other fields in this struct (e.g., + * ContentLength, TransferEncoding, Trailer), the field values are + * authoritative. + * + * Keys in the map are canonicalized (see CanonicalHeaderKey). + */ + header: Header + /** + * Body represents the response body. + * + * The response body is streamed on demand as the Body field + * is read. If the network connection fails or the server + * terminates the response, Body.Read calls return an error. + * + * The http Client and Transport guarantee that Body is always + * non-nil, even on responses without a body or responses with + * a zero-length body. It is the caller's responsibility to + * close Body. The default HTTP client's Transport may not + * reuse HTTP/1.x "keep-alive" TCP connections if the Body is + * not read to completion and closed. + * + * The Body is automatically dechunked if the server replied + * with a "chunked" Transfer-Encoding. + * + * As of Go 1.12, the Body will also implement io.Writer + * on a successful "101 Switching Protocols" response, + * as used by WebSockets and HTTP/2's "h2c" mode. + */ + body: io.ReadCloser + /** + * ContentLength records the length of the associated content. The + * value -1 indicates that the length is unknown. Unless Request.Method + * is "HEAD", values >= 0 indicate that the given number of bytes may + * be read from Body. + */ + contentLength: number + /** + * Contains transfer encodings from outer-most to inner-most. Value is + * nil, means that "identity" encoding is used. + */ + transferEncoding: Array + /** + * Close records whether the header directed that the connection be + * closed after reading Body. The value is advice for clients: neither + * ReadResponse nor Response.Write ever closes a connection. + */ + close: boolean + /** + * Uncompressed reports whether the response was sent compressed but + * was decompressed by the http package. When true, reading from + * Body yields the uncompressed content instead of the compressed + * content actually set from the server, ContentLength is set to -1, + * and the "Content-Length" and "Content-Encoding" fields are deleted + * from the responseHeader. To get the original response from + * the server, set Transport.DisableCompression to true. + */ + uncompressed: boolean + /** + * Trailer maps trailer keys to values in the same + * format as Header. + * + * The Trailer initially contains only nil values, one for + * each key specified in the server's "Trailer" header + * value. Those values are not added to Header. + * + * Trailer must not be accessed concurrently with Read calls + * on the Body. + * + * After Body.Read has returned io.EOF, Trailer will contain + * any trailer values sent by the server. + */ + trailer: Header + /** + * Request is the request that was sent to obtain this Response. + * Request's Body is nil (having already been consumed). + * This is only populated for Client requests. + */ + request?: Request + /** + * TLS contains information about the TLS connection on which the + * response was received. It is nil for unencrypted responses. + * The pointer is shared between responses and should not be + * modified. + */ + tls?: any + } + interface Response { + /** + * Cookies parses and returns the cookies set in the Set-Cookie headers. + */ + cookies(): Array<(Cookie | undefined)> + } + interface Response { + /** + * Location returns the URL of the response's "Location" header, + * if present. Relative redirects are resolved relative to + * [Response.Request]. [ErrNoLocation] is returned if no + * Location header is present. + */ + location(): (url.URL) + } + interface Response { + /** + * ProtoAtLeast reports whether the HTTP protocol used + * in the response is at least major.minor. + */ + protoAtLeast(major: number, minor: number): boolean + } + interface Response { + /** + * Write writes r to w in the HTTP/1.x server response format, + * including the status line, headers, body, and optional trailer. + * + * This method consults the following fields of the response r: + * + * ``` + * StatusCode + * ProtoMajor + * ProtoMinor + * Request.Method + * TransferEncoding + * Trailer + * Body + * ContentLength + * Header, values for non-canonical keys will have unpredictable behavior + * ``` + * + * The Response Body is closed after it is sent. + */ + write(w: io.Writer): void + } + /** + * A ConnState represents the state of a client connection to a server. + * It's used by the optional [Server.ConnState] hook. + */ + interface ConnState extends Number{} + interface ConnState { + string(): string + } +} + +namespace store { +} + +namespace jwt { + /** + * NumericDate represents a JSON numeric date value, as referenced at + * https://datatracker.ietf.org/doc/html/rfc7519#section-2. + */ + type _sSHpXWx = time.Time + interface NumericDate extends _sSHpXWx { + } + interface NumericDate { + /** + * MarshalJSON is an implementation of the json.RawMessage interface and serializes the UNIX epoch + * represented in NumericDate to a byte array, using the precision specified in TimePrecision. + */ + marshalJSON(): string|Array + } + interface NumericDate { + /** + * UnmarshalJSON is an implementation of the json.RawMessage interface and + * deserializes a [NumericDate] from a JSON representation, i.e. a + * [json.Number]. This number represents an UNIX epoch with either integer or + * non-integer seconds. + */ + unmarshalJSON(b: string|Array): void + } + /** + * ClaimStrings is basically just a slice of strings, but it can be either + * serialized from a string array or just a string. This type is necessary, + * since the "aud" claim can either be a single string or an array. + */ + interface ClaimStrings extends Array{} + interface ClaimStrings { + unmarshalJSON(data: string|Array): void + } + interface ClaimStrings { + marshalJSON(): string|Array + } +} + +namespace hook { + /** + * wrapped local Hook embedded struct to limit the public API surface. + */ + type _sdhIAaE = Hook + interface mainHook extends _sdhIAaE { + } +} + +namespace types { +} + +namespace search { +} + +namespace router { + // @ts-ignore + import validation = ozzo_validation + /** + * RouterGroup represents a collection of routes and other sub groups + * that share common pattern prefix and middlewares. + */ + interface RouterGroup { + prefix: string + middlewares: Array<(hook.Handler | undefined)> + } + interface RouterGroup { + /** + * Group creates and register a new child Group into the current one + * with the specified prefix. + * + * The prefix follows the standard Go net/http ServeMux pattern format ("[HOST]/[PATH]") + * and will be concatenated recursively into the final route path, meaning that + * only the root level group could have HOST as part of the prefix. + * + * Returns the newly created group to allow chaining and registering + * sub-routes and group specific middlewares. + */ + group(prefix: string): (RouterGroup) + } + interface RouterGroup { + /** + * BindFunc registers one or multiple middleware functions to the current group. + * + * The registered middleware functions are "anonymous" and with default priority, + * aka. executes in the order they were registered. + * + * If you need to specify a named middleware (ex. so that it can be removed) + * or middleware with custom exec prirority, use [RouterGroup.Bind] method. + */ + bindFunc(...middlewareFuncs: ((e: T) => void)[]): (RouterGroup) + } + interface RouterGroup { + /** + * Bind registers one or multiple middleware handlers to the current group. + */ + bind(...middlewares: (hook.Handler | undefined)[]): (RouterGroup) + } + interface RouterGroup { + /** + * Unbind removes one or more middlewares with the specified id(s) + * from the current group and its children (if any). + * + * Anonymous middlewares are not removable, aka. this method does nothing + * if the middleware id is an empty string. + */ + unbind(...middlewareIds: string[]): (RouterGroup) + } + interface RouterGroup { + /** + * Route registers a single route into the current group. + * + * Note that the final route path will be the concatenation of all parent groups prefixes + the route path. + * The path follows the standard Go net/http ServeMux format ("[HOST]/[PATH]"), + * meaning that only a top level group route could have HOST as part of the prefix. + * + * Returns the newly created route to allow attaching route-only middlewares. + */ + route(method: string, path: string, action: (e: T) => void): (Route) + } + interface RouterGroup { + /** + * Any is a shorthand for [RouterGroup.AddRoute] with "" as route method (aka. matches any method). + */ + any(path: string, action: (e: T) => void): (Route) + } + interface RouterGroup { + /** + * GET is a shorthand for [RouterGroup.AddRoute] with GET as route method. + */ + get(path: string, action: (e: T) => void): (Route) + } + interface RouterGroup { + /** + * SEARCH is a shorthand for [RouterGroup.AddRoute] with SEARCH as route method. + */ + search(path: string, action: (e: T) => void): (Route) + } + interface RouterGroup { + /** + * POST is a shorthand for [RouterGroup.AddRoute] with POST as route method. + */ + post(path: string, action: (e: T) => void): (Route) + } + interface RouterGroup { + /** + * DELETE is a shorthand for [RouterGroup.AddRoute] with DELETE as route method. + */ + delete(path: string, action: (e: T) => void): (Route) + } + interface RouterGroup { + /** + * PATCH is a shorthand for [RouterGroup.AddRoute] with PATCH as route method. + */ + patch(path: string, action: (e: T) => void): (Route) + } + interface RouterGroup { + /** + * PUT is a shorthand for [RouterGroup.AddRoute] with PUT as route method. + */ + put(path: string, action: (e: T) => void): (Route) + } + interface RouterGroup { + /** + * HEAD is a shorthand for [RouterGroup.AddRoute] with HEAD as route method. + */ + head(path: string, action: (e: T) => void): (Route) + } + interface RouterGroup { + /** + * OPTIONS is a shorthand for [RouterGroup.AddRoute] with OPTIONS as route method. + */ + options(path: string, action: (e: T) => void): (Route) + } + interface RouterGroup { + /** + * HasRoute checks whether the specified route pattern (method + path) + * is registered in the current group or its children. + * + * This could be useful to conditionally register and checks for routes + * in order prevent panic on duplicated routes. + * + * Note that routes with anonymous and named wildcard placeholder are treated as equal, + * aka. "GET /abc/" is considered the same as "GET /abc/{something...}". + */ + hasRoute(method: string, path: string): boolean + } +} + +/** + * Package oauth2 provides support for making + * OAuth2 authorized and authenticated HTTP requests, + * as specified in RFC 6749. + * It can additionally grant authorization with Bearer JWT. */ +namespace oauth2 { + /** + * An AuthCodeOption is passed to Config.AuthCodeURL. + */ + interface AuthCodeOption { + [key:string]: any; + } + /** + * Token represents the credentials used to authorize + * the requests to access protected resources on the OAuth 2.0 + * provider's backend. + * + * Most users of this package should not access fields of Token + * directly. They're exported mostly for use by related packages + * implementing derivative OAuth2 flows. + */ + interface Token { + /** + * AccessToken is the token that authorizes and authenticates + * the requests. + */ + accessToken: string + /** + * TokenType is the type of token. + * The Type method returns either this or "Bearer", the default. + */ + tokenType: string + /** + * RefreshToken is a token that's used by the application + * (as opposed to the user) to refresh the access token + * if it expires. + */ + refreshToken: string + /** + * Expiry is the optional expiration time of the access token. + * + * If zero, [TokenSource] implementations will reuse the same + * token forever and RefreshToken or equivalent + * mechanisms for that TokenSource will not be used. + */ + expiry: time.Time + /** + * ExpiresIn is the OAuth2 wire format "expires_in" field, + * which specifies how many seconds later the token expires, + * relative to an unknown time base approximately around "now". + * It is the application's responsibility to populate + * `Expiry` from `ExpiresIn` when required. + */ + expiresIn: number + } + interface Token { + /** + * Type returns t.TokenType if non-empty, else "Bearer". + */ + type(): string + } + interface Token { + /** + * SetAuthHeader sets the Authorization header to r using the access + * token in t. + * + * This method is unnecessary when using [Transport] or an HTTP Client + * returned by this package. + */ + setAuthHeader(r: http.Request): void + } + interface Token { + /** + * WithExtra returns a new [Token] that's a clone of t, but using the + * provided raw extra map. This is only intended for use by packages + * implementing derivative OAuth2 flows. + */ + withExtra(extra: any): (Token) + } + interface Token { + /** + * Extra returns an extra field. + * Extra fields are key-value pairs returned by the server as + * part of the token retrieval response. + */ + extra(key: string): any + } + interface Token { + /** + * Valid reports whether t is non-nil, has an AccessToken, and is not expired. + */ + valid(): boolean + } +} + +namespace subscriptions { +} + +namespace cobra { + interface PositionalArgs {(cmd: Command, args: Array): void } + // @ts-ignore + import flag = pflag + /** + * FParseErrWhitelist configures Flag parse errors to be ignored + */ + interface FParseErrWhitelist extends _TygojaAny{} + /** + * Group Structure to manage groups for commands + */ + interface Group { + id: string + title: string + } + /** + * CompletionOptions are the options to control shell completion + */ + interface CompletionOptions { + /** + * DisableDefaultCmd prevents Cobra from creating a default 'completion' command + */ + disableDefaultCmd: boolean + /** + * DisableNoDescFlag prevents Cobra from creating the '--no-descriptions' flag + * for shells that support completion descriptions + */ + disableNoDescFlag: boolean + /** + * DisableDescriptions turns off all completion descriptions for shells + * that support them + */ + disableDescriptions: boolean + /** + * HiddenDefaultCmd makes the default 'completion' command hidden + */ + hiddenDefaultCmd: boolean + /** + * DefaultShellCompDirective sets the ShellCompDirective that is returned + * if no special directive can be determined + */ + defaultShellCompDirective?: ShellCompDirective + } + interface CompletionOptions { + setDefaultShellCompDirective(directive: ShellCompDirective): void + } + /** + * Completion is a string that can be used for completions + * + * two formats are supported: + * ``` + * - the completion choice + * - the completion choice with a textual description (separated by a TAB). + * ``` + * + * [CompletionWithDesc] can be used to create a completion string with a textual description. + * + * Note: Go type alias is used to provide a more descriptive name in the documentation, but any string can be used. + */ + interface Completion extends String{} + /** + * CompletionFunc is a function that provides completion results. + */ + interface CompletionFunc {(cmd: Command, args: Array, toComplete: string): [Array, ShellCompDirective] } +} + +namespace slog { + /** + * An Attr is a key-value pair. + */ + interface Attr { + key: string + value: Value + } + interface Attr { + /** + * Equal reports whether a and b have equal keys and values. + */ + equal(b: Attr): boolean + } + interface Attr { + string(): string + } + /** + * A Handler handles log records produced by a Logger. + * + * A typical handler may print log records to standard error, + * or write them to a file or database, or perhaps augment them + * with additional attributes and pass them on to another handler. + * + * Any of the Handler's methods may be called concurrently with itself + * or with other methods. It is the responsibility of the Handler to + * manage this concurrency. + * + * Users of the slog package should not invoke Handler methods directly. + * They should use the methods of [Logger] instead. + */ + interface Handler { + [key:string]: any; + /** + * Enabled reports whether the handler handles records at the given level. + * The handler ignores records whose level is lower. + * It is called early, before any arguments are processed, + * to save effort if the log event should be discarded. + * If called from a Logger method, the first argument is the context + * passed to that method, or context.Background() if nil was passed + * or the method does not take a context. + * The context is passed so Enabled can use its values + * to make a decision. + */ + enabled(_arg0: context.Context, _arg1: Level): boolean + /** + * Handle handles the Record. + * It will only be called when Enabled returns true. + * The Context argument is as for Enabled. + * It is present solely to provide Handlers access to the context's values. + * Canceling the context should not affect record processing. + * (Among other things, log messages may be necessary to debug a + * cancellation-related problem.) + * + * Handle methods that produce output should observe the following rules: + * ``` + * - If r.Time is the zero time, ignore the time. + * - If r.PC is zero, ignore it. + * - Attr's values should be resolved. + * - If an Attr's key and value are both the zero value, ignore the Attr. + * This can be tested with attr.Equal(Attr{}). + * - If a group's key is empty, inline the group's Attrs. + * - If a group has no Attrs (even if it has a non-empty key), + * ignore it. + * ``` + */ + handle(_arg0: context.Context, _arg1: Record): void + /** + * WithAttrs returns a new Handler whose attributes consist of + * both the receiver's attributes and the arguments. + * The Handler owns the slice: it may retain, modify or discard it. + */ + withAttrs(attrs: Array): Handler + /** + * WithGroup returns a new Handler with the given group appended to + * the receiver's existing groups. + * The keys of all subsequent attributes, whether added by With or in a + * Record, should be qualified by the sequence of group names. + * + * How this qualification happens is up to the Handler, so long as + * this Handler's attribute keys differ from those of another Handler + * with a different sequence of group names. + * + * A Handler should treat WithGroup as starting a Group of Attrs that ends + * at the end of the log event. That is, + * + * ``` + * logger.WithGroup("s").LogAttrs(ctx, level, msg, slog.Int("a", 1), slog.Int("b", 2)) + * ``` + * + * should behave like + * + * ``` + * logger.LogAttrs(ctx, level, msg, slog.Group("s", slog.Int("a", 1), slog.Int("b", 2))) + * ``` + * + * If the name is empty, WithGroup returns the receiver. + */ + withGroup(name: string): Handler + } + /** + * A Level is the importance or severity of a log event. + * The higher the level, the more important or severe the event. + */ + interface Level extends Number{} + interface Level { + /** + * String returns a name for the level. + * If the level has a name, then that name + * in uppercase is returned. + * If the level is between named values, then + * an integer is appended to the uppercased name. + * Examples: + * + * ``` + * LevelWarn.String() => "WARN" + * (LevelInfo+2).String() => "INFO+2" + * ``` + */ + string(): string + } + interface Level { + /** + * MarshalJSON implements [encoding/json.Marshaler] + * by quoting the output of [Level.String]. + */ + marshalJSON(): string|Array + } + interface Level { + /** + * UnmarshalJSON implements [encoding/json.Unmarshaler] + * It accepts any string produced by [Level.MarshalJSON], + * ignoring case. + * It also accepts numeric offsets that would result in a different string on + * output. For example, "Error-8" would marshal as "INFO". + */ + unmarshalJSON(data: string|Array): void + } + interface Level { + /** + * AppendText implements [encoding.TextAppender] + * by calling [Level.String]. + */ + appendText(b: string|Array): string|Array + } + interface Level { + /** + * MarshalText implements [encoding.TextMarshaler] + * by calling [Level.AppendText]. + */ + marshalText(): string|Array + } + interface Level { + /** + * UnmarshalText implements [encoding.TextUnmarshaler]. + * It accepts any string produced by [Level.MarshalText], + * ignoring case. + * It also accepts numeric offsets that would result in a different string on + * output. For example, "Error-8" would marshal as "INFO". + */ + unmarshalText(data: string|Array): void + } + interface Level { + /** + * Level returns the receiver. + * It implements [Leveler]. + */ + level(): Level + } + // @ts-ignore + import loginternal = internal +} + +namespace cron { + /** + * Job defines a single registered cron job. + */ + interface Job { + } + interface Job { + /** + * Id returns the cron job id. + */ + id(): string + } + interface Job { + /** + * Expression returns the plain cron job schedule expression. + */ + expression(): string + } + interface Job { + /** + * Run runs the cron job function. + */ + run(): void + } + interface Job { + /** + * MarshalJSON implements [json.Marshaler] and export the current + * jobs data into valid JSON. + */ + marshalJSON(): string|Array + } +} + +namespace slog { + // @ts-ignore + import loginternal = internal + /** + * A Record holds information about a log event. + * Copies of a Record share state. + * Do not modify a Record after handing out a copy to it. + * Call [NewRecord] to create a new Record. + * Use [Record.Clone] to create a copy with no shared state. + */ + interface Record { + /** + * The time at which the output method (Log, Info, etc.) was called. + */ + time: time.Time + /** + * The log message. + */ + message: string + /** + * The level of the event. + */ + level: Level + /** + * The program counter at the time the record was constructed, as determined + * by runtime.Callers. If zero, no program counter is available. + * + * The only valid use for this value is as an argument to + * [runtime.CallersFrames]. In particular, it must not be passed to + * [runtime.FuncForPC]. + */ + pc: number + } + interface Record { + /** + * Clone returns a copy of the record with no shared state. + * The original record and the clone can both be modified + * without interfering with each other. + */ + clone(): Record + } + interface Record { + /** + * NumAttrs returns the number of attributes in the [Record]. + */ + numAttrs(): number + } + interface Record { + /** + * Attrs calls f on each Attr in the [Record]. + * Iteration stops if f returns false. + */ + attrs(f: (_arg0: Attr) => boolean): void + } + interface Record { + /** + * AddAttrs appends the given Attrs to the [Record]'s list of Attrs. + * It omits empty groups. + */ + addAttrs(...attrs: Attr[]): void + } + interface Record { + /** + * Add converts the args to Attrs as described in [Logger.Log], + * then appends the Attrs to the [Record]'s list of Attrs. + * It omits empty groups. + */ + add(...args: any[]): void + } + /** + * A Value can represent any Go value, but unlike type any, + * it can represent most small values without an allocation. + * The zero Value corresponds to nil. + */ + interface Value { + } + interface Value { + /** + * Kind returns v's Kind. + */ + kind(): Kind + } + interface Value { + /** + * Any returns v's value as an any. + */ + any(): any + } + interface Value { + /** + * String returns Value's value as a string, formatted like [fmt.Sprint]. Unlike + * the methods Int64, Float64, and so on, which panic if v is of the + * wrong kind, String never panics. + */ + string(): string + } + interface Value { + /** + * Int64 returns v's value as an int64. It panics + * if v is not a signed integer. + */ + int64(): number + } + interface Value { + /** + * Uint64 returns v's value as a uint64. It panics + * if v is not an unsigned integer. + */ + uint64(): number + } + interface Value { + /** + * Bool returns v's value as a bool. It panics + * if v is not a bool. + */ + bool(): boolean + } + interface Value { + /** + * Duration returns v's value as a [time.Duration]. It panics + * if v is not a time.Duration. + */ + duration(): time.Duration + } + interface Value { + /** + * Float64 returns v's value as a float64. It panics + * if v is not a float64. + */ + float64(): number + } + interface Value { + /** + * Time returns v's value as a [time.Time]. It panics + * if v is not a time.Time. + */ + time(): time.Time + } + interface Value { + /** + * LogValuer returns v's value as a LogValuer. It panics + * if v is not a LogValuer. + */ + logValuer(): LogValuer + } + interface Value { + /** + * Group returns v's value as a []Attr. + * It panics if v's [Kind] is not [KindGroup]. + */ + group(): Array + } + interface Value { + /** + * Equal reports whether v and w represent the same Go value. + */ + equal(w: Value): boolean + } + interface Value { + /** + * Resolve repeatedly calls LogValue on v while it implements [LogValuer], + * and returns the result. + * If v resolves to a group, the group's attributes' values are not recursively + * resolved. + * If the number of LogValue calls exceeds a threshold, a Value containing an + * error is returned. + * Resolve's return value is guaranteed not to be of Kind [KindLogValuer]. + */ + resolve(): Value + } +} + +namespace url { + /** + * The Userinfo type is an immutable encapsulation of username and + * password details for a [URL]. An existing Userinfo value is guaranteed + * to have a username set (potentially empty, as allowed by RFC 2396), + * and optionally a password. + */ + interface Userinfo { + } + interface Userinfo { + /** + * Username returns the username. + */ + username(): string + } + interface Userinfo { + /** + * Password returns the password in case it is set, and whether it is set. + */ + password(): [string, boolean] + } + interface Userinfo { + /** + * String returns the encoded userinfo information in the standard form + * of "username[:password]". + */ + string(): string + } +} + +namespace multipart { + /** + * A Part represents a single part in a multipart body. + */ + interface Part { + /** + * The headers of the body, if any, with the keys canonicalized + * in the same fashion that the Go http.Request headers are. + * For example, "foo-bar" changes case to "Foo-Bar" + */ + header: textproto.MIMEHeader + } + interface Part { + /** + * FormName returns the name parameter if p has a Content-Disposition + * of type "form-data". Otherwise it returns the empty string. + */ + formName(): string + } + interface Part { + /** + * FileName returns the filename parameter of the [Part]'s Content-Disposition + * header. If not empty, the filename is passed through filepath.Base (which is + * platform dependent) before being returned. + */ + fileName(): string + } + interface Part { + /** + * Read reads the body of a part, after its headers and before the + * next part (if any) begins. + */ + read(d: string|Array): number + } + interface Part { + close(): void + } +} + +namespace http { + /** + * SameSite allows a server to define a cookie attribute making it impossible for + * the browser to send this cookie along with cross-site requests. The main + * goal is to mitigate the risk of cross-origin information leakage, and provide + * some protection against cross-site request forgery attacks. + * + * See https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00 for details. + */ + interface SameSite extends Number{} + // @ts-ignore + import mathrand = rand + // @ts-ignore + import urlpkg = url +} + +namespace router { + // @ts-ignore + import validation = ozzo_validation + interface Route { + action: (e: T) => void + method: string + path: string + middlewares: Array<(hook.Handler | undefined)> + } + interface Route { + /** + * BindFunc registers one or multiple middleware functions to the current route. + * + * The registered middleware functions are "anonymous" and with default priority, + * aka. executes in the order they were registered. + * + * If you need to specify a named middleware (ex. so that it can be removed) + * or middleware with custom exec prirority, use the [Route.Bind] method. + */ + bindFunc(...middlewareFuncs: ((e: T) => void)[]): (Route) + } + interface Route { + /** + * Bind registers one or multiple middleware handlers to the current route. + */ + bind(...middlewares: (hook.Handler | undefined)[]): (Route) + } + interface Route { + /** + * Unbind removes one or more middlewares with the specified id(s) from the current route. + * + * It also adds the removed middleware ids to an exclude list so that they could be skipped from + * the execution chain in case the middleware is registered in a parent group. + * + * Anonymous middlewares are considered non-removable, aka. this method + * does nothing if the middleware id is an empty string. + */ + unbind(...middlewareIds: string[]): (Route) + } +} + +namespace oauth2 { +} + +namespace cobra { + // @ts-ignore + import flag = pflag + /** + * ShellCompDirective is a bit map representing the different behaviors the shell + * can be instructed to have once completions have been provided. + */ + interface ShellCompDirective extends Number{} +} + namespace slog { // @ts-ignore import loginternal = internal @@ -20715,3 +23842,8 @@ namespace slog { logValue(): Value } } + +namespace router { + // @ts-ignore + import validation = ozzo_validation +} diff --git a/pb/pb_hooks/cron.pb.js b/pocketbase/pb_hooks/cron.pb.js similarity index 100% rename from pb/pb_hooks/cron.pb.js rename to pocketbase/pb_hooks/cron.pb.js diff --git a/pb/pb_hooks/main.pb.js b/pocketbase/pb_hooks/main.pb.js similarity index 100% rename from pb/pb_hooks/main.pb.js rename to pocketbase/pb_hooks/main.pb.js diff --git a/pocketbase/pb_migrations/.gitkeep b/pocketbase/pb_migrations/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/pb/pb_migrations/1745466760_collections_snapshot.js b/pocketbase/pb_migrations/1766179464_collections_snapshot.js similarity index 85% rename from pb/pb_migrations/1745466760_collections_snapshot.js rename to pocketbase/pb_migrations/1766179464_collections_snapshot.js index b7e229f..dc62eb0 100644 --- a/pb/pb_migrations/1745466760_collections_snapshot.js +++ b/pocketbase/pb_migrations/1766179464_collections_snapshot.js @@ -400,7 +400,7 @@ migrate((app) => { { "authAlert": { "emailTemplate": { - "body": "

Hello,

\n

We noticed a login to your {APP_NAME} account from a new location.

\n

If this was you, you may disregard this email.

\n

If this wasn't you, you should immediately change your {APP_NAME} account password to revoke access from all other locations.

\n

\n Thanks,
\n {APP_NAME} team\n

", + "body": "

Hello,

\n

We noticed a login to your {APP_NAME} account from a new location:

\n

{ALERT_INFO}

\n

If this wasn't you, you should immediately change your {APP_NAME} account password to revoke access from all other locations.

\n

If this was you, you may disregard this email.

\n

\n Thanks,
\n {APP_NAME} team\n

", "subject": "Login from a new location" }, "enabled": true @@ -572,7 +572,7 @@ migrate((app) => { { "authAlert": { "emailTemplate": { - "body": "

Hello,

\n

We noticed a login to your {APP_NAME} account from a new location.

\n

If this was you, you may disregard this email.

\n

If this wasn't you, you should immediately change your {APP_NAME} account password to revoke access from all other locations.

\n

\n Thanks,
\n {APP_NAME} team\n

", + "body": "

Hello,

\n

We noticed a login to your {APP_NAME} account from a new location:

\n

{ALERT_INFO}

\n

If this wasn't you, you should immediately change your {APP_NAME} account password to revoke access from all other locations.

\n

If this was you, you may disregard this email.

\n

\n Thanks,
\n {APP_NAME} team\n

", "subject": "Login from a new location" }, "enabled": true @@ -721,8 +721,8 @@ migrate((app) => { }, "id": "_pb_users_auth_", "indexes": [ - "CREATE UNIQUE INDEX `idx_tokenKey__pb_users_auth_` ON `Users` (`tokenKey`)", - "CREATE UNIQUE INDEX `idx_email__pb_users_auth_` ON `Users` (`email`) WHERE `email` != ''" + "CREATE UNIQUE INDEX `idx_tokenKey__pb_users_auth_` ON `users` (`tokenKey`)", + "CREATE UNIQUE INDEX `idx_email__pb_users_auth_` ON `users` (`email`) WHERE `email` != ''" ], "listRule": "id = @request.auth.id", "manageRule": null, @@ -731,7 +731,7 @@ migrate((app) => { "enabled": false, "rule": "" }, - "name": "Users", + "name": "users", "oauth2": { "enabled": false, "mappedFields": { @@ -774,136 +774,6 @@ migrate((app) => { "duration": 259200 }, "viewRule": "id = @request.auth.id" - }, - { - "createRule": "", - "deleteRule": null, - "fields": [ - { - "autogeneratePattern": "[a-z0-9]{15}", - "hidden": false, - "id": "text3208210256", - "max": 15, - "min": 15, - "name": "id", - "pattern": "^[a-z0-9]+$", - "presentable": false, - "primaryKey": true, - "required": true, - "system": true, - "type": "text" - }, - { - "autogeneratePattern": "", - "hidden": false, - "id": "text724990059", - "max": 0, - "min": 0, - "name": "title", - "pattern": "", - "presentable": false, - "primaryKey": false, - "required": false, - "system": false, - "type": "text" - }, - { - "autogeneratePattern": "", - "hidden": false, - "id": "text4274335913", - "max": 0, - "min": 0, - "name": "content", - "pattern": "", - "presentable": false, - "primaryKey": false, - "required": true, - "system": false, - "type": "text" - }, - { - "autogeneratePattern": "", - "hidden": false, - "id": "text3458754147", - "max": 0, - "min": 0, - "name": "summary", - "pattern": "", - "presentable": false, - "primaryKey": false, - "required": false, - "system": false, - "type": "text" - }, - { - "autogeneratePattern": "", - "hidden": false, - "id": "text2063623452", - "max": 0, - "min": 0, - "name": "status", - "pattern": "", - "presentable": false, - "primaryKey": false, - "required": true, - "system": false, - "type": "text" - }, - { - "cascadeDelete": false, - "collectionId": "_pb_users_auth_", - "hidden": false, - "id": "relation765557111", - "maxSelect": 1, - "minSelect": 0, - "name": "User", - "presentable": false, - "required": true, - "system": false, - "type": "relation" - }, - { - "cascadeDelete": false, - "collectionId": "_pb_users_auth_", - "hidden": false, - "id": "relation3456166728", - "maxSelect": 999, - "minSelect": 0, - "name": "SubscriberUsers", - "presentable": false, - "required": false, - "system": false, - "type": "relation" - }, - { - "hidden": false, - "id": "autodate2990389176", - "name": "created", - "onCreate": true, - "onUpdate": false, - "presentable": false, - "system": false, - "type": "autodate" - }, - { - "hidden": false, - "id": "autodate3332085495", - "name": "updated", - "onCreate": true, - "onUpdate": true, - "presentable": false, - "system": false, - "type": "autodate" - } - ], - "id": "pbc_3853224427", - "indexes": [], - "listRule": "", - "name": "Projects", - "system": false, - "type": "base", - "updateRule": null, - "viewRule": "" } ]; diff --git a/pocketbase/pb_migrations/1766191749_created_projects.js b/pocketbase/pb_migrations/1766191749_created_projects.js new file mode 100644 index 0000000..1b0c859 --- /dev/null +++ b/pocketbase/pb_migrations/1766191749_created_projects.js @@ -0,0 +1,68 @@ +/// +migrate((app) => { + // UP MIGRATION + + // Create new collections + const collection_projects_create = new Collection({ + name: "projects", + type: "base", + listRule: "@request.auth.id != \"\"", + viewRule: "@request.auth.id != \"\" && (User = @request.auth.id || SubscriberUsers ?= @request.auth.id)", + createRule: "@request.auth.id != \"\"", + updateRule: "@request.auth.id != \"\" && User = @request.auth.id", + deleteRule: "@request.auth.id != \"\" && User = @request.auth.id", + manageRule: null, + fields: [ + { + name: "title", + type: "text", + required: true, + }, + { + name: "content", + type: "text", + required: true, + }, + { + name: "status", + type: "select", + required: true, + values: ["draft", "active", "complete", "fail"], + }, + { + name: "summary", + type: "text", + required: false, + }, + { + name: "User", + type: "relation", + required: true, + collectionId: "_pb_users_auth_", + maxSelect: 1, + minSelect: 0, + cascadeDelete: false, + }, + { + name: "SubscriberUsers", + type: "relation", + required: true, + collectionId: "_pb_users_auth_", + maxSelect: 999, + minSelect: 0, + cascadeDelete: false, + }, + ], + indexes: [], + }); + + return app.save(collection_projects_create); + +}, (app) => { + // DOWN MIGRATION (ROLLBACK) + + // Delete created collections + const collection_projects_rollback = app.findCollectionByNameOrId("projects"); + return app.delete(collection_projects_rollback); + +}); diff --git a/scripts/dev-setup.sh b/scripts/dev-setup.sh new file mode 100755 index 0000000..ef94e0f --- /dev/null +++ b/scripts/dev-setup.sh @@ -0,0 +1,141 @@ +#!/bin/bash +set -euo pipefail + +DEFAULT_PB_VERSION="0.34.2" +PB_VERSION="${PB_VERSION:-$DEFAULT_PB_VERSION}" +PB_PATH="./pocketbase" + +# Load superuser credentials from .env file if it exists +if [ -f ".env" ]; then + echo "Loading superuser credentials from .env file..." + # shellcheck disable=SC2046 + export $(grep -E "^PB_SUPERUSER_EMAIL=" .env | xargs) + # shellcheck disable=SC2046 + export $(grep -E "^PB_SUPERUSER_PASSWORD=" .env | xargs) +fi + +# Determine operating system +detect_os() { + case $(uname -s) in + Linux*) echo "linux" ;; + Darwin*) echo "darwin" ;; + CYGWIN*|MINGW*|MSYS*) echo "windows" ;; + *) echo "Unsupported operating system: $(uname -s)" >&2; exit 1 ;; + esac +} + +# Determine architecture +detect_arch() { + case $(uname -m) in + x86_64) echo "amd64" ;; + arm64|aarch64) echo "arm64" ;; + *) echo "Unsupported architecture: $(uname -m)" >&2; exit 1 ;; + esac +} + +TARGETOS=$(detect_os) +TARGETARCH=$(detect_arch) + +# Download and extract PocketBase +download_pocketbase() { + echo "Downloading PocketBase v${PB_VERSION} for ${TARGETOS} (${TARGETARCH})..." + mkdir -p "${PB_PATH}/tmp" + + local url="https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_${TARGETOS}_${TARGETARCH}.zip" + local zip_file="${PB_PATH}/tmp/pb.zip" + + if command -v wget >/dev/null 2>&1; then + wget -q "$url" -O "$zip_file" + else + curl -sL "$url" -o "$zip_file" + fi + + yes | unzip -o "$zip_file" -d "${PB_PATH}/" >/dev/null + rm "$zip_file" + echo "PocketBase v${PB_VERSION} installed successfully" +} + +# Check and install PocketBase +if [ ! -d "${PB_PATH}" ]; then + echo "Creating pocketbase directory..." + mkdir -p "${PB_PATH}" + download_pocketbase +elif [ -f "${PB_PATH}/pocketbase" ]; then + CURRENT_VERSION=$("${PB_PATH}/pocketbase" --version 2>&1 | sed 's/^.*version //' | sed 's/^v//') + if [ "$CURRENT_VERSION" != "$PB_VERSION" ]; then + echo "Updating PocketBase from v${CURRENT_VERSION} to v${PB_VERSION}..." + rm -f "${PB_PATH}/pocketbase" + download_pocketbase + else + echo "PocketBase is already at version ${PB_VERSION}" + fi +else + echo "PocketBase executable not found, downloading..." + download_pocketbase +fi + +# Ensure required directories exist +mkdir -p "${PB_PATH}/pb_migrations" +mkdir -p "${PB_PATH}/pb_data" +mkdir -p "${PB_PATH}/pb_hooks" + +echo "PocketBase directories initialized" + +# Initialize PocketBase database +echo "Initializing PocketBase database..." +"${PB_PATH}/pocketbase" migrate up 2>/dev/null || true + +# Generate snapshot if none exists +SNAPSHOT_COUNT=$(find "${PB_PATH}/pb_migrations" -name "*_collections_snapshot.js" -o -name "*_snapshot.js" 2>/dev/null | wc -l | tr -d ' ') + +if [ "$SNAPSHOT_COUNT" -eq 0 ]; then + echo "No snapshots found. Generating initial snapshot from PocketBase..." + echo "y" | "${PB_PATH}/pocketbase" migrate collections >/dev/null + + SNAPSHOT_COUNT=$(find "${PB_PATH}/pb_migrations" -name "*_collections_snapshot.js" -o -name "*_snapshot.js" 2>/dev/null | wc -l | tr -d ' ') + if [ "$SNAPSHOT_COUNT" -gt 0 ]; then + echo "Snapshot generated successfully (found ${SNAPSHOT_COUNT} snapshot(s))" + else + echo "Warning: No snapshot file found after generation" + fi +else + echo "Snapshots already exist (found ${SNAPSHOT_COUNT} snapshot(s)). Skipping snapshot generation." +fi + +# Create superuser if credentials are provided +create_superuser() { + local email="${PB_SUPERUSER_EMAIL:-}" + local password="${PB_SUPERUSER_PASSWORD:-}" + + if [ -z "$email" ] || [ -z "$password" ]; then + echo "Superuser credentials not provided or incomplete. Skipping superuser creation." + return + fi + + echo "Superuser credentials provided. Validating..." + + # Validate email format + if ! echo "$email" | grep -qE '^[^ ]+@[^ ]+\.[^ ]+$'; then + echo "Email validation failed: Invalid email format." + return + fi + + # Validate password length + if [ ${#password} -lt 10 ]; then + echo "Password validation failed: Password must be at least 10 characters long." + return + fi + + echo "Credentials valid. Attempting to create superuser..." + + if "${PB_PATH}/pocketbase" superuser upsert "$email" "$password"; then + echo "Superuser created successfully or already exists." + else + echo "Failed to create superuser. Check PocketBase logs for details." + fi +} + +create_superuser + +echo "Setup complete!" + diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh new file mode 100755 index 0000000..3fceba4 --- /dev/null +++ b/scripts/entrypoint.sh @@ -0,0 +1,75 @@ +#!/bin/sh +set -euo pipefail + +# Display version information if available +if [ -n "${VERSION:-}" ]; then + echo "Starting application version: $VERSION" +fi + +# Wait for PocketBase lock files to be released +wait_for_lock_files() { + local timeout=3 + local interval=1 + local attempt=1 + local max_attempts=$((timeout / interval)) + + while [ $attempt -le $max_attempts ]; do + if [ ! -f "/pocketbase/pb_data/auxiliary.db-shm" ] && \ + [ ! -f "/pocketbase/pb_data/auxiliary.db-wal" ] && \ + [ ! -f "/pocketbase/pb_data/data.db-shm" ] && \ + [ ! -f "/pocketbase/pb_data/data.db-wal" ]; then + echo "All lock files are gone." + break + fi + + echo "Lock files present, waiting $interval seconds (attempt $attempt/$max_attempts)..." + sleep $interval + attempt=$((attempt + 1)) + done + + if [ $attempt -gt $max_attempts ]; then + echo "Timeout reached after $timeout seconds. Lock files still present. Starting server anyway." + else + echo "Starting server..." + fi +} + +wait_for_lock_files + +# Create superuser if credentials are provided +create_superuser() { + local email="${PB_SUPERUSER_EMAIL:-}" + local password="${PB_SUPERUSER_PASSWORD:-}" + + if [ -z "$email" ] || [ -z "$password" ]; then + echo "Superuser credentials not provided or incomplete. Skipping superuser creation." + return + fi + + echo "Superuser credentials provided. Validating..." + + # Validate email format + if ! echo "$email" | grep -qE '^[^ ]+@[^ ]+\.[^ ]+$'; then + echo "Email validation failed: Invalid email format." + return + fi + + # Validate password length + if [ ${#password} -lt 10 ]; then + echo "Password validation failed: Password must be at least 10 characters long." + return + fi + + echo "Credentials valid. Attempting to create superuser..." + + if /pocketbase/pocketbase superuser upsert "$email" "$password"; then + echo "Superuser created successfully or already exists." + else + echo "Failed to create superuser. Check PocketBase logs for details." + fi +} + +create_superuser + +exec "$@" + diff --git a/scripts/migrate-pb-data.sh b/scripts/migrate-pb-data.sh new file mode 100755 index 0000000..6cc275d --- /dev/null +++ b/scripts/migrate-pb-data.sh @@ -0,0 +1,80 @@ +#!/bin/bash +set -euo pipefail + +OLD_DIR="./pocket_base" +NEW_DIR="./pocketbase" + +echo "🔄 PocketBase Data Migration Helper" +echo "" + +# Check if old directory exists +if [ ! -d "$OLD_DIR" ]; then + echo "✅ No old pocket_base directory found - nothing to migrate" + exit 0 +fi + +# Check if new directory exists +if [ ! -d "$NEW_DIR" ]; then + echo "❌ New ./pocketbase directory not found. Please run 'yarn setup' first." + exit 1 +fi + +echo "Found old PocketBase directory. This script will help you migrate your data." +echo "" +echo "⚠️ WARNING: This will overwrite any existing data in ./pocketbase/pb_data/" +echo "" +read -p "Do you want to migrate your data? (y/N): " -n 1 -r +echo "" + +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Migration cancelled." + exit 0 +fi + +# Backup existing pb_data if it exists +if [ -d "$NEW_DIR/pb_data" ]; then + BACKUP_DIR="$NEW_DIR/pb_data_backup_$(date +%Y%m%d_%H%M%S)" + echo "📦 Backing up existing data to $BACKUP_DIR" + cp -r "$NEW_DIR/pb_data" "$BACKUP_DIR" +fi + +# Copy database files +echo "📋 Copying database files..." + +if [ -f "$OLD_DIR/pb_data/data.db" ]; then + cp "$OLD_DIR/pb_data/data.db" "$NEW_DIR/pb_data/" + echo " ✅ data.db copied" +fi + +if [ -f "$OLD_DIR/pb_data/auxiliary.db" ]; then + cp "$OLD_DIR/pb_data/auxiliary.db" "$NEW_DIR/pb_data/" + echo " ✅ auxiliary.db copied" +fi + +# Copy storage directory +if [ -d "$OLD_DIR/pb_data/storage" ]; then + echo "📁 Copying storage directory..." + mkdir -p "$NEW_DIR/pb_data/storage" + cp -r "$OLD_DIR/pb_data/storage/"* "$NEW_DIR/pb_data/storage/" 2>/dev/null || true + echo " ✅ storage copied" +fi + +# Copy types +if [ -f "$OLD_DIR/pb_data/types.d.ts" ]; then + cp "$OLD_DIR/pb_data/types.d.ts" "$NEW_DIR/pb_data/" + echo " ✅ types.d.ts copied" +fi + +# Copy executable if needed +if [ -f "$OLD_DIR/pocketbase" ] && [ ! -f "$NEW_DIR/pocketbase" ]; then + echo "📦 Copying PocketBase executable..." + cp "$OLD_DIR/pocketbase" "$NEW_DIR/" + echo " ✅ pocketbase executable copied" +fi + +echo "" +echo "✅ Migration complete!" +echo "" +echo "You can now safely remove the old directory with:" +echo " rm -rf $OLD_DIR" + diff --git a/scripts/pb-migrate.sh b/scripts/pb-migrate.sh new file mode 100755 index 0000000..d7a090d --- /dev/null +++ b/scripts/pb-migrate.sh @@ -0,0 +1,73 @@ +#!/bin/bash +set -euo pipefail + +PB_PATH="./pocketbase" +PB_MIGRATIONS="${PB_PATH}/pb_migrations" + +echo "🚀 Starting PocketBase migration process..." + +# Ensure migration directory exists +mkdir -p "${PB_MIGRATIONS}" + +# Step 1: Generate migrations from schema +echo "" +echo "📝 Step 1: Checking for schema changes and generating migrations..." + +if [ ! -d "shared" ]; then + echo "❌ Error: shared directory not found" + exit 1 +fi + +cd shared +GEN_OUTPUT=$(yarn migrate:generate 2>&1 || true) +echo "$GEN_OUTPUT" + +if echo "$GEN_OUTPUT" | grep -qiE "created|generated|migration.*\.js"; then + echo "✓ New migration(s) generated" +else + echo "✓ No migrations needed (schema is in sync)" +fi +cd - > /dev/null + +# Step 2: Apply migrations to PocketBase +echo "" +echo "🔄 Step 2: Applying migrations to PocketBase..." + +if ! "${PB_PATH}/pocketbase" migrate up; then + echo "❌ Failed to apply migrations" + exit 1 +fi + +echo "✓ Migrations applied successfully" + +# Step 3: Verify migration success +echo "" +echo "✅ Step 3: Verifying schema synchronization..." + +cd shared +STATUS_OUTPUT=$(yarn migrate:status 2>&1 || true) +cd - > /dev/null + +SYNC_PATTERNS="schema is in sync|no differences|everything is up to date|no changes|in sync|synchronized" +DIFF_PATTERNS="difference|change|migration|new|modified|deleted" + +if echo "$STATUS_OUTPUT" | grep -qiE "$SYNC_PATTERNS"; then + if ! echo "$STATUS_OUTPUT" | grep -qiE "$DIFF_PATTERNS"; then + echo "✓ Schema verification passed - database is in sync with schemas" + echo "" + echo "🎉 Migration process completed successfully!" + exit 0 + fi +fi + +# Report differences if found +echo "⚠️ Schema verification found differences:" +echo "$STATUS_OUTPUT" +echo "" +echo "This might indicate:" +echo " 1. The migration didn't fully apply" +echo " 2. There are additional schema changes not yet migrated" +echo "" +echo "Run 'yarn migrate:status' for more details" +exit 1 + diff --git a/scripts/rename-project.js b/scripts/rename-project.js new file mode 100755 index 0000000..945abe6 --- /dev/null +++ b/scripts/rename-project.js @@ -0,0 +1,371 @@ +#!/usr/bin/env node + +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import { execSync } from 'child_process'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const rootDir = path.resolve(__dirname, '..'); + +// ANSI color codes for fun output +const colors = { + reset: '\x1b[0m', + bright: '\x1b[1m', + red: '\x1b[31m', + green: '\x1b[32m', + yellow: '\x1b[33m', + blue: '\x1b[34m', + magenta: '\x1b[35m', + cyan: '\x1b[36m', +}; + +const { bright, green, yellow, blue, magenta, cyan, red, reset } = colors; + +// Fun ASCII art +const logo = ` +${magenta}╔═══════════════════════════════════════════════════════════════╗${reset} +${magenta}║${reset} ${cyan}🚀 PROJECT RENAMER 3000${reset} ${magenta}║${reset} +${magenta}║${reset} ${yellow}Transform your template into something awesome!${reset} ${magenta}║${reset} +${magenta}╚═══════════════════════════════════════════════════════════════╝${reset} +`; + +function log(message, color = reset) { + console.log(`${color}${message}${reset}`); +} + +function logStep(step, message) { + log(`${bright}${blue}[${step}]${reset} ${message}`); +} + +function logSuccess(message) { + log(`${green}✅ ${message}${reset}`); +} + +function logWarning(message) { + log(`${yellow}⚠️ ${message}${reset}`); +} + +function logError(message) { + log(`${red}❌ ${message}${reset}`); +} + +// Validation functions +function validateProjectName(name) { + if (!name) { + throw new Error('Project name is required'); + } + + if (!/^[a-z0-9-]+$/.test(name)) { + throw new Error('Project name must contain only lowercase letters, numbers, and hyphens'); + } + + if (name.length < 2) { + throw new Error('Project name must be at least 2 characters long'); + } + + if (name.length > 50) { + throw new Error('Project name must be less than 50 characters long'); + } + + if (name.startsWith('-') || name.endsWith('-')) { + throw new Error('Project name cannot start or end with a hyphen'); + } + + return true; +} + +function validateScopeName(scope) { + if (!scope) { + throw new Error('Scope name is required'); + } + + if (!/^[a-z0-9-]+$/.test(scope)) { + throw new Error('Scope name must contain only lowercase letters, numbers, and hyphens'); + } + + if (scope.length < 2) { + throw new Error('Scope name must be at least 2 characters long'); + } + + if (scope.length > 30) { + throw new Error('Scope name must be less than 30 characters long'); + } + + return true; +} + +// File processing functions +function updateJsonFile(filePath, updater) { + if (!fs.existsSync(filePath)) { + logWarning(`File not found: ${filePath}`); + return; + } + + try { + const content = fs.readFileSync(filePath, 'utf8'); + const json = JSON.parse(content); + const updated = updater(json); + fs.writeFileSync(filePath, JSON.stringify(updated, null, 2) + '\n'); + logSuccess(`Updated ${path.relative(rootDir, filePath)}`); + } catch (error) { + logError(`Failed to update ${filePath}: ${error.message}`); + } +} + +function updateTextFile(filePath, replacements) { + if (!fs.existsSync(filePath)) { + logWarning(`File not found: ${filePath}`); + return; + } + + try { + let content = fs.readFileSync(filePath, 'utf8'); + let changed = false; + + for (const [search, replace] of replacements) { + const regex = new RegExp(search, 'g'); + if (regex.test(content)) { + content = content.replace(regex, replace); + changed = true; + } + } + + if (changed) { + fs.writeFileSync(filePath, content); + logSuccess(`Updated ${path.relative(rootDir, filePath)}`); + } + } catch (error) { + logError(`Failed to update ${filePath}: ${error.message}`); + } +} + +function getReplacements(projectName, scopeName) { + return [ + // Package names + ['fullstack-pb-template', projectName], + ['@project/', `@${scopeName}/`], + + // Docker image names + ['dastro/fullstack-pb-template', `${scopeName}/${projectName}`], + + // Documentation references + ['FULLSTACK-PB-TEMPLATE', projectName.toUpperCase()], + ['Fullstack is a comprehensive', `${projectName} is a comprehensive`], + + // Workspace references in commands + [`yarn workspace @project/`, `yarn workspace @${scopeName}/`], + [`yarn focus @project/`, `yarn focus @${scopeName}/`], + + // Import statements + [`from '@project/shared`, `from '@${scopeName}/shared`], + [`import.*@project/shared`, `import.*@${scopeName}/shared`], + ]; +} + +async function main() { + console.log(logo); + + // Get command line arguments + const args = process.argv.slice(2); + let projectName = args[0]; + let scopeName = args[1]; + + // Interactive prompts if not provided + if (!projectName) { + const readline = await import('readline'); + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }); + + const question = (prompt) => new Promise((resolve) => { + rl.question(prompt, resolve); + }); + + log(`${bright}Let's set up your awesome project!${reset}\n`); + + projectName = await question(`${cyan}📦 What's your project name? ${yellow}(e.g., my-awesome-app)${reset}: `); + scopeName = await question(`${cyan}🏷️ What's your npm scope? ${yellow}(e.g., mycompany)${reset}: `); + + rl.close(); + } + + // Validate inputs + try { + validateProjectName(projectName); + validateScopeName(scopeName); + } catch (error) { + logError(error.message); + process.exit(1); + } + + log(`\n${bright}Configuration:${reset}`); + log(` ${blue}Project Name:${reset} ${projectName}`); + log(` ${blue}Scope Name:${reset} @${scopeName}`); + log(` ${blue}Workspaces:${reset} @${scopeName}/app, @${scopeName}/functions, @${scopeName}/shared\n`); + + // Confirm before proceeding + if (!args[0]) { + const readline = await import('readline'); + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }); + + const confirm = await new Promise((resolve) => { + rl.question(`${yellow}Continue with this configuration? ${bright}(y/N)${reset}: `, resolve); + }); + + rl.close(); + + if (confirm.toLowerCase() !== 'y' && confirm.toLowerCase() !== 'yes') { + log(`${yellow}Operation cancelled.${reset}`); + process.exit(0); + } + } + + const replacements = getReplacements(projectName, scopeName); + + // Step 1: Update package.json files + logStep('1/6', 'Updating package.json files...'); + + // Root package.json + updateJsonFile(path.join(rootDir, 'package.json'), (json) => ({ + ...json, + name: projectName, + scripts: { + ...json.scripts, + 'migrate:generate': `yarn workspace @${scopeName}/shared migrate:generate`, + 'migrate:status': `yarn workspace @${scopeName}/shared migrate:status`, + dev: `concurrently "yarn workspace @${scopeName}/shared dev" "yarn workspace @${scopeName}/app dev" "yarn workspace @${scopeName}/functions dev" "./pocketbase/pocketbase serve --http=\\"0.0.0.0:8080\\""`, + } + })); + + // App package.json + updateJsonFile(path.join(rootDir, 'app/package.json'), (json) => ({ + ...json, + name: `@${scopeName}/app`, + dependencies: { + ...json.dependencies, + [`@${scopeName}/shared`]: 'workspace:*' + } + })); + + // Functions package.json + updateJsonFile(path.join(rootDir, 'functions/package.json'), (json) => ({ + ...json, + name: `@${scopeName}/functions`, + dependencies: { + ...json.dependencies, + [`@${scopeName}/shared`]: 'workspace:*' + } + })); + + // Shared package.json + updateJsonFile(path.join(rootDir, 'shared/package.json'), (json) => ({ + ...json, + name: `@${scopeName}/shared`, + description: `Shared zod schemas for ${projectName}` + })); + + // Step 2: Update README files + logStep('2/6', 'Updating documentation...'); + + updateTextFile(path.join(rootDir, 'README.md'), replacements); + updateTextFile(path.join(rootDir, 'functions/README.md'), replacements); + + // Step 3: Update GitHub workflows + logStep('3/6', 'Updating GitHub workflows...'); + + const workflowFiles = [ + '.github/workflows/release-please.yml', + '.github/workflows/nightly-docker-build.yml', + '.github/workflows/docker-publish.yml' + ]; + + workflowFiles.forEach(file => { + updateTextFile(path.join(rootDir, file), replacements); + }); + + // Step 4: Update steering files + logStep('4/6', 'Updating steering documentation...'); + + const steeringFiles = [ + '.kiro/steering/tech.md', + '.kiro/steering/structure.md', + '.kiro/steering/schema-driven-migrations.md' + ]; + + steeringFiles.forEach(file => { + updateTextFile(path.join(rootDir, file), replacements); + }); + + // Step 5: Clean up yarn.lock and node_modules + logStep('5/6', 'Cleaning up dependencies...'); + + try { + // Remove yarn.lock to force regeneration with new package names + if (fs.existsSync(path.join(rootDir, 'yarn.lock'))) { + fs.unlinkSync(path.join(rootDir, 'yarn.lock')); + logSuccess('Removed yarn.lock'); + } + + // Remove node_modules directories + const nodeModulesDirs = [ + 'node_modules', + 'app/node_modules', + 'functions/node_modules', + 'shared/node_modules' + ]; + + nodeModulesDirs.forEach(dir => { + const fullPath = path.join(rootDir, dir); + if (fs.existsSync(fullPath)) { + fs.rmSync(fullPath, { recursive: true, force: true }); + logSuccess(`Removed ${dir}`); + } + }); + } catch (error) { + logWarning(`Failed to clean dependencies: ${error.message}`); + } + + // Step 6: Reinstall dependencies + logStep('6/6', 'Reinstalling dependencies...'); + + try { + execSync('yarn install', { + cwd: rootDir, + stdio: 'inherit', + timeout: 120000 // 2 minutes timeout + }); + logSuccess('Dependencies reinstalled successfully'); + } catch (error) { + logError('Failed to reinstall dependencies. Please run "yarn install" manually.'); + } + + // Success message + log(`\n${green}${bright}🎉 Project renamed successfully!${reset}\n`); + + log(`${bright}Your project is now configured as:${reset}`); + log(` ${blue}📦 Project:${reset} ${projectName}`); + log(` ${blue}🏷️ Scope:${reset} @${scopeName}`); + log(` ${blue}🔧 Workspaces:${reset}`); + log(` • @${scopeName}/app (React frontend)`); + log(` • @${scopeName}/functions (Express backend)`); + log(` • @${scopeName}/shared (Shared library)`); + + log(`\n${bright}Next steps:${reset}`); + log(` ${cyan}1.${reset} Update your git remote: ${yellow}git remote set-url origin ${reset}`); + log(` ${cyan}2.${reset} Start development: ${yellow}yarn dev${reset}`); + log(` ${cyan}3.${reset} Build your awesome project! ${magenta}🚀${reset}`); + + log(`\n${bright}Happy coding! 🎯${reset}`); +} + +// Run the script +main().catch((error) => { + logError(`Unexpected error: ${error.message}`); + process.exit(1); +}); \ No newline at end of file diff --git a/shared/README.md b/shared/README.md index 4bf160f..72bb101 100644 --- a/shared/README.md +++ b/shared/README.md @@ -1,6 +1,24 @@ -# Schema Package +# Shared Package -This package contains shared [Zod](https://github.com/colinhacks/zod) schemas for use across the project. These schemas provide runtime validation and TypeScript type inference. +This package contains shared [Zod](https://github.com/colinhacks/zod) schemas and utilities for use across the project. These schemas provide runtime validation, TypeScript type inference, and serve as the source of truth for PocketBase database migrations. + +## Features + +- **Zod Schemas**: Runtime validation and TypeScript types +- **Schema-Driven Migrations**: Automatic PocketBase migration generation +- **Shared Utilities**: Common functions and types across workspaces +- **Type Safety**: Full TypeScript support with type inference + +## Documentation + +### Migration System +- **[Migration Guide](./MIGRATION_GUIDE.md)** - Complete guide for schema-driven migrations +- **[Type Mapping Reference](./TYPE_MAPPING.md)** - Zod to PocketBase type conversions +- **[Naming Conventions](./NAMING_CONVENTIONS.md)** - Collection and field naming rules +- **[Configuration Reference](./CONFIGURATION.md)** - Configuration options and settings + +### Examples +- **[Schema Examples](./src/schema/)** - Example schema definitions ## Usage @@ -61,15 +79,68 @@ const createData = createTodoSchema.parse({ }); ``` +## Schema-Driven Migrations + +This package includes a powerful migration system that automatically generates PocketBase migrations from your Zod schemas. + +### Quick Start + +```bash +# Generate migration from schema changes +yarn migrate:generate + +# Check migration status +yarn migrate:status +``` + +### How It Works + +1. Define Zod schemas in `src/schema/` +2. Run `yarn migrate:generate` +3. System compares with previous snapshot +4. Generates PocketBase migration files +5. PocketBase applies migrations on startup + +For complete documentation, see the [Migration Guide](./MIGRATION_GUIDE.md). + ## Available Schemas -- `todoSchema`: Defines the structure of a Todo item -- `createTodoSchema`: Schema for creating a new Todo -- `updateTodoSchema`: Schema for updating an existing Todo +Current schemas in this package: + +- `UserSchema` / `UserInputSchema` - User entity with auth +- `ProjectSchema` / `ProjectInputSchema` - Project entity +- `baseSchema` - Base fields for all entities ## Adding New Schemas -1. Create a new file in the `src` directory (e.g., `src/user.ts`) -2. Define your schema using Zod -3. Export the schema and any related types -4. Add the export to `src/index.ts` \ No newline at end of file +1. Create a new file in `src/schema/` (e.g., `src/schema/article.ts`) +2. Define your schema using Zod: + +```typescript +import { z } from "zod"; +import { baseSchema } from "./base"; + +export const ArticleInputSchema = z.object({ + title: z.string().min(5).max(200), + content: z.string(), + User: z.string(), // Relation to Users collection +}); + +export const ArticleSchema = ArticleInputSchema.extend(baseSchema); +``` + +3. Export the schema in `src/schema/index.ts` +4. Generate migration: `yarn migrate:generate` +5. Start PocketBase to apply: `yarn pb` + +### Schema Naming Conventions + +- **File name** determines collection name (pluralized automatically) + - `article.ts` → `Articles` collection + - `user.ts` → `Users` collection +- **Relation fields** detected by naming: + - `User: z.string()` → single relation to Users + - `Tags: z.array(z.string())` → multiple relation to Tags +- **Auth collections** detected by `email` field presence + +For more details, see the [Migration Guide](./MIGRATION_GUIDE.md) \ No newline at end of file diff --git a/shared/package.json b/shared/package.json index b9d1e17..b24f1c7 100644 --- a/shared/package.json +++ b/shared/package.json @@ -31,18 +31,27 @@ "scripts": { "build": "tsup", "dev": "nodemon", + "test": "vitest", "typecheck": "tsc --noEmit", - "format": "prettier --write ./src" + "format": "prettier --write ./src", + "migrate:generate": "npx pocketbase-migrate generate", + "migrate:status": "npx pocketbase-migrate status" }, "license": "MIT", "devDependencies": { + "@babel/parser": "^7.28.5", "@types/node": "^22.14.1", + "diff": "^8.0.2", + "fast-check": "^4.3.0", "nodemon": "^3.1.9", "tsup": "^8.4.0", - "typescript": "^5.8.3" + "tsx": "^4.19.3", + "typescript": "^5.8.3", + "vitest": "^3.1.2" }, "dependencies": { "pocketbase": "^0.26.0", + "pocketbase-zod-schema": "^0.2.1", "zod": "^3.24.3" } } diff --git a/shared/pocketbase-migrate.config.js b/shared/pocketbase-migrate.config.js new file mode 100644 index 0000000..ae479d8 --- /dev/null +++ b/shared/pocketbase-migrate.config.js @@ -0,0 +1,15 @@ +export default { + schema: { + directory: "./src/schema", + exclude: ["*.test.ts", "*.spec.ts", "base.ts", "index.ts"], + }, + migrations: { + directory: "../pocketbase/pb_migrations", + format: "js", + }, + diff: { + warnOnDelete: true, + requireForceForDestructive: true, + }, +}; + diff --git a/shared/src/__tests__/exports.test.ts b/shared/src/__tests__/exports.test.ts new file mode 100644 index 0000000..1329428 --- /dev/null +++ b/shared/src/__tests__/exports.test.ts @@ -0,0 +1,96 @@ +/** + * Test to verify all permission-related exports are accessible + */ +import { describe, expect, it } from "vitest"; +import { z } from "zod"; +import { + PermissionTemplates, + resolveTemplate, + withPermissions, + type APIRuleType, + type PermissionSchema, + type PermissionTemplate, + type PermissionTemplateConfig, + type RuleExpression, +} from "../schema/index"; + +describe("Permission Exports", () => { + it("should export withPermissions helper", () => { + expect(withPermissions).toBeDefined(); + expect(typeof withPermissions).toBe("function"); + }); + + it("should export PermissionTemplates", () => { + expect(PermissionTemplates).toBeDefined(); + expect(typeof PermissionTemplates.public).toBe("function"); + expect(typeof PermissionTemplates.authenticated).toBe("function"); + expect(typeof PermissionTemplates.ownerOnly).toBe("function"); + expect(typeof PermissionTemplates.adminOnly).toBe("function"); + expect(typeof PermissionTemplates.readPublic).toBe("function"); + }); + + it("should export resolveTemplate function", () => { + expect(resolveTemplate).toBeDefined(); + expect(typeof resolveTemplate).toBe("function"); + }); + + it("should allow using withPermissions with a schema", () => { + const testSchema = z.object({ + title: z.string(), + User: z.string(), + }); + + const schemaWithPermissions = withPermissions(testSchema, { + template: "owner-only", + ownerField: "User", + }); + + expect(schemaWithPermissions).toBeDefined(); + expect(schemaWithPermissions._def.description).toBeDefined(); + }); + + it("should allow using PermissionTemplates directly", () => { + const publicRules = PermissionTemplates.public(); + expect(publicRules.listRule).toBe(""); + expect(publicRules.viewRule).toBe(""); + expect(publicRules.createRule).toBe(""); + + const authRules = PermissionTemplates.authenticated(); + expect(authRules.listRule).toBe('@request.auth.id != ""'); + + const ownerRules = PermissionTemplates.ownerOnly("User"); + expect(ownerRules.listRule).toContain("User = @request.auth.id"); + }); + + it("should allow using resolveTemplate", () => { + const config: PermissionTemplateConfig = { + template: "owner-only", + ownerField: "User", + customRules: { + listRule: '@request.auth.id != ""', + }, + }; + + const resolved = resolveTemplate(config); + expect(resolved.listRule).toBe('@request.auth.id != ""'); + expect(resolved.viewRule).toContain("User = @request.auth.id"); + }); + + it("should allow type usage", () => { + // This test verifies that types are properly exported and can be used + const schema: PermissionSchema = { + listRule: '@request.auth.id != ""', + viewRule: null, + createRule: "", + }; + + const ruleType: APIRuleType = "listRule"; + const expression: RuleExpression = '@request.auth.id != ""'; + const template: PermissionTemplate = "owner-only"; + + expect(schema).toBeDefined(); + expect(ruleType).toBe("listRule"); + expect(expression).toBe('@request.auth.id != ""'); + expect(template).toBe("owner-only"); + }); +}); diff --git a/shared/src/schema/base.ts b/shared/src/schema/base.ts deleted file mode 100644 index eb0c5b9..0000000 --- a/shared/src/schema/base.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { z } from "zod"; - -export const baseSchema = { - id: z.string().describe("unique id"), - collectionId: z.string().describe("collection id"), - collectionName: z.string().describe("collection name"), - created: z.string().describe("created timestamp"), - updated: z.string().describe("updated timestamp"), - expand: z.record(z.any()).describe("expandable fields"), -}; - -export const baseImageFileSchema = { - ...baseSchema, - thumbnailURL: z.string().optional(), - imageFiles: z.array(z.string()), -}; - -export const inputImageFileSchema = { - imageFiles: z.array(z.instanceof(File)), -}; - -export const omitImageFilesSchema = { - imageFiles: true, -} as const; diff --git a/shared/src/schema/index.ts b/shared/src/schema/index.ts index 17b3c74..57e5a6e 100644 --- a/shared/src/schema/index.ts +++ b/shared/src/schema/index.ts @@ -1,3 +1,2 @@ -export * from "./base"; export * from "./project"; export * from "./user"; diff --git a/shared/src/schema/project.ts b/shared/src/schema/project.ts index 5845136..eabfba3 100644 --- a/shared/src/schema/project.ts +++ b/shared/src/schema/project.ts @@ -1,6 +1,6 @@ import { z } from "zod"; import { StatusEnum } from "../enums"; -import { baseImageFileSchema, inputImageFileSchema, omitImageFilesSchema } from "./base"; +import { baseImageFileSchema, inputImageFileSchema, omitImageFilesSchema, withPermissions } from "pocketbase-zod-schema"; export const ProjectInputSchema = z .object({ @@ -14,4 +14,20 @@ export const ProjectInputSchema = z SubscriberUsers: z.array(z.string()), }) .extend(inputImageFileSchema); -export const ProjectSchema = ProjectInputSchema.omit(omitImageFilesSchema).extend(baseImageFileSchema); + +// Apply permissions using template with custom overrides +// Uses 'owner-only' template but allows all authenticated users to list projects +// This allows users to see all projects but only manage their own +export const ProjectSchema = withPermissions( + ProjectInputSchema.omit(omitImageFilesSchema).extend(baseImageFileSchema), + { + template: "owner-only", + ownerField: "User", + customRules: { + // Override list rule to allow authenticated users to see all projects + listRule: '@request.auth.id != ""', + // Allow viewing if user is owner OR a subscriber + viewRule: '@request.auth.id != "" && (User = @request.auth.id || SubscriberUsers ?= @request.auth.id)', + }, + } +); diff --git a/shared/src/schema/user.ts b/shared/src/schema/user.ts index 0dcc141..24be118 100644 --- a/shared/src/schema/user.ts +++ b/shared/src/schema/user.ts @@ -1,12 +1,46 @@ +import { baseSchema, withIndexes, withPermissions } from "pocketbase-zod-schema"; import { z } from "zod"; -import { baseSchema } from "./base"; /** -- User Collections -- */ +// Input schema for forms (includes passwordConfirm for validation) export const UserInputSchema = z.object({ - name: z.string().min(2, "Name must be longer"), + name: z.string().optional(), email: z.string().email(), - username: z.string().min(6, "Username must be longer"), - password: z.string().min(6, "Password must be at least 8 characters"), + password: z.string().min(8, "Password must be at least 8 characters"), passwordConfirm: z.string(), + avatar: z.instanceof(File).optional(), }); -export const UserSchema = UserInputSchema.extend(baseSchema); + +// Database schema (excludes passwordConfirm, includes avatar as file field) +// Matches PocketBase's default users auth collection structure +// Note: PocketBase has min: 0, max: 255 for name, but our snapshot loader +// doesn't extract field-level options properly yet (TODO: fix snapshot loader) +const UserDatabaseSchema = z.object({ + name: z.string().optional(), + email: z.string().email(), + password: z.string().min(8, "Password must be at least 8 characters"), + avatar: z.instanceof(File).optional(), +}); + +// Apply permissions and indexes for auth collection +// Matches PocketBase's default users collection configuration +export const UserSchema = withIndexes( + withPermissions(UserDatabaseSchema.extend(baseSchema), { + // Users can list their own profile + listRule: "id = @request.auth.id", + // Users can view their own profile + viewRule: "id = @request.auth.id", + // Anyone can create an account (sign up) + createRule: "", + // Users can only update their own profile + updateRule: "id = @request.auth.id", + // Users can only delete their own account + deleteRule: "id = @request.auth.id", + // manageRule is null in PocketBase default (not set) + }), + [ + // PocketBase's default indexes for auth collections + "CREATE UNIQUE INDEX `idx_tokenKey__pb_users_auth_` ON `users` (`tokenKey`)", + "CREATE UNIQUE INDEX `idx_email__pb_users_auth_` ON `users` (`email`) WHERE `email` != ''", + ] +); diff --git a/shared/tsconfig.json b/shared/tsconfig.json index 538142e..7a9f069 100644 --- a/shared/tsconfig.json +++ b/shared/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "ES2020", "module": "ESNext", - "moduleResolution": "node", + "moduleResolution": "bundler", "esModuleInterop": true, "strict": true, "declaration": true, diff --git a/shared/tsup.config.ts b/shared/tsup.config.ts index 159a43b..e4f97c3 100644 --- a/shared/tsup.config.ts +++ b/shared/tsup.config.ts @@ -3,13 +3,16 @@ import { defineConfig } from 'tsup'; export default defineConfig({ entry: [ 'src/schema.ts', + 'src/schema/user.ts', + 'src/schema/project.ts', 'src/enums.ts', 'src/types.ts', - 'src/mutator.ts' + 'src/mutator.ts', ], format: ['esm'], dts: true, splitting: false, sourcemap: true, clean: true, + shims: true, }); \ No newline at end of file diff --git a/shared/vitest.config.ts b/shared/vitest.config.ts new file mode 100644 index 0000000..8e730d5 --- /dev/null +++ b/shared/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + }, +}); diff --git a/yarn.lock b/yarn.lock index 8688286..df5be75 100644 --- a/yarn.lock +++ b/yarn.lock @@ -126,6 +126,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.27.1": + version: 7.27.1 + resolution: "@babel/helper-string-parser@npm:7.27.1" + checksum: 10c0/8bda3448e07b5583727c103560bcf9c4c24b3c1051a4c516d4050ef69df37bb9a4734a585fe12725b8c2763de0a265aa1e909b485a4e3270b7cfd3e4dbe4b602 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-validator-identifier@npm:7.25.9" @@ -133,6 +140,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/helper-validator-identifier@npm:7.28.5" + checksum: 10c0/42aaebed91f739a41f3d80b72752d1f95fd7c72394e8e4bd7cdd88817e0774d80a432451bcba17c2c642c257c483bf1d409dd4548883429ea9493a3bc4ab0847 + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.25.9": version: 7.25.9 resolution: "@babel/helper-validator-option@npm:7.25.9" @@ -161,6 +175,17 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/parser@npm:7.28.5" + dependencies: + "@babel/types": "npm:^7.28.5" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/5bbe48bf2c79594ac02b490a41ffde7ef5aa22a9a88ad6bcc78432a6ba8a9d638d531d868bd1f104633f1f6bba9905746e15185b8276a3756c42b765d131b1ef + languageName: node + linkType: hard + "@babel/plugin-transform-react-jsx-self@npm:^7.25.9": version: 7.25.9 resolution: "@babel/plugin-transform-react-jsx-self@npm:7.25.9" @@ -237,6 +262,16 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/types@npm:7.28.5" + dependencies: + "@babel/helper-string-parser": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.28.5" + checksum: 10c0/a5a483d2100befbf125793640dec26b90b95fd233a94c19573325898a5ce1e52cdfa96e495c7dcc31b5eca5b66ce3e6d4a0f5a4a62daec271455959f208ab08a + languageName: node + linkType: hard + "@chakra-ui/anatomy@npm:2.3.6": version: 2.3.6 resolution: "@chakra-ui/anatomy@npm:2.3.6" @@ -493,6 +528,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/aix-ppc64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/aix-ppc64@npm:0.27.2" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/android-arm64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/android-arm64@npm:0.25.1" @@ -500,6 +542,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/android-arm64@npm:0.27.2" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/android-arm@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/android-arm@npm:0.25.1" @@ -507,6 +556,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/android-arm@npm:0.27.2" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@esbuild/android-x64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/android-x64@npm:0.25.1" @@ -514,6 +570,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-x64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/android-x64@npm:0.27.2" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + "@esbuild/darwin-arm64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/darwin-arm64@npm:0.25.1" @@ -521,6 +584,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-arm64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/darwin-arm64@npm:0.27.2" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/darwin-x64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/darwin-x64@npm:0.25.1" @@ -528,6 +598,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-x64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/darwin-x64@npm:0.27.2" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@esbuild/freebsd-arm64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/freebsd-arm64@npm:0.25.1" @@ -535,6 +612,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-arm64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/freebsd-arm64@npm:0.27.2" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/freebsd-x64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/freebsd-x64@npm:0.25.1" @@ -542,6 +626,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-x64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/freebsd-x64@npm:0.27.2" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/linux-arm64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/linux-arm64@npm:0.25.1" @@ -549,6 +640,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/linux-arm64@npm:0.27.2" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/linux-arm@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/linux-arm@npm:0.25.1" @@ -556,6 +654,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/linux-arm@npm:0.27.2" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@esbuild/linux-ia32@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/linux-ia32@npm:0.25.1" @@ -563,6 +668,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ia32@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/linux-ia32@npm:0.27.2" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/linux-loong64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/linux-loong64@npm:0.25.1" @@ -570,6 +682,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-loong64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/linux-loong64@npm:0.27.2" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + "@esbuild/linux-mips64el@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/linux-mips64el@npm:0.25.1" @@ -577,6 +696,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-mips64el@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/linux-mips64el@npm:0.27.2" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + "@esbuild/linux-ppc64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/linux-ppc64@npm:0.25.1" @@ -584,6 +710,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ppc64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/linux-ppc64@npm:0.27.2" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/linux-riscv64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/linux-riscv64@npm:0.25.1" @@ -591,6 +724,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-riscv64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/linux-riscv64@npm:0.27.2" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + "@esbuild/linux-s390x@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/linux-s390x@npm:0.25.1" @@ -598,6 +738,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-s390x@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/linux-s390x@npm:0.27.2" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + "@esbuild/linux-x64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/linux-x64@npm:0.25.1" @@ -605,6 +752,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-x64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/linux-x64@npm:0.27.2" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + "@esbuild/netbsd-arm64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/netbsd-arm64@npm:0.25.1" @@ -612,6 +766,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-arm64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/netbsd-arm64@npm:0.27.2" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/netbsd-x64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/netbsd-x64@npm:0.25.1" @@ -619,6 +780,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-x64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/netbsd-x64@npm:0.27.2" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/openbsd-arm64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/openbsd-arm64@npm:0.25.1" @@ -626,6 +794,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-arm64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/openbsd-arm64@npm:0.27.2" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/openbsd-x64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/openbsd-x64@npm:0.25.1" @@ -633,6 +808,20 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-x64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/openbsd-x64@npm:0.27.2" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openharmony-arm64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/openharmony-arm64@npm:0.27.2" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/sunos-x64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/sunos-x64@npm:0.25.1" @@ -640,6 +829,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/sunos-x64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/sunos-x64@npm:0.27.2" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + "@esbuild/win32-arm64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/win32-arm64@npm:0.25.1" @@ -647,6 +843,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-arm64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/win32-arm64@npm:0.27.2" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/win32-ia32@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/win32-ia32@npm:0.25.1" @@ -654,6 +857,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-ia32@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/win32-ia32@npm:0.27.2" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/win32-x64@npm:0.25.1": version: 0.25.1 resolution: "@esbuild/win32-x64@npm:0.25.1" @@ -661,6 +871,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-x64@npm:0.27.2": + version: 0.27.2 + resolution: "@esbuild/win32-x64@npm:0.27.2" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": version: 4.5.1 resolution: "@eslint-community/eslint-utils@npm:4.5.1" @@ -1026,11 +1243,17 @@ __metadata: version: 0.0.0-use.local resolution: "@project/shared@workspace:shared" dependencies: + "@babel/parser": "npm:^7.28.5" "@types/node": "npm:^22.14.1" + diff: "npm:^8.0.2" + fast-check: "npm:^4.3.0" nodemon: "npm:^3.1.9" pocketbase: "npm:^0.26.0" + pocketbase-zod-schema: "npm:^0.2.1" tsup: "npm:^8.4.0" + tsx: "npm:^4.19.3" typescript: "npm:^5.8.3" + vitest: "npm:^3.1.2" zod: "npm:^3.24.3" languageName: unknown linkType: soft @@ -2537,6 +2760,13 @@ __metadata: languageName: node linkType: hard +"chalk@npm:^5.3.0": + version: 5.6.2 + resolution: "chalk@npm:5.6.2" + checksum: 10c0/99a4b0f0e7991796b1e7e3f52dceb9137cae2a9dfc8fc0784a550dc4c558e15ab32ed70b14b21b52beb2679b4892b41a0aa44249bcb996f01e125d58477c6976 + languageName: node + linkType: hard + "check-error@npm:^2.1.1": version: 2.1.1 resolution: "check-error@npm:2.1.1" @@ -2579,6 +2809,22 @@ __metadata: languageName: node linkType: hard +"cli-cursor@npm:^5.0.0": + version: 5.0.0 + resolution: "cli-cursor@npm:5.0.0" + dependencies: + restore-cursor: "npm:^5.0.0" + checksum: 10c0/7ec62f69b79f6734ab209a3e4dbdc8af7422d44d360a7cb1efa8a0887bbe466a6e625650c466fe4359aee44dbe2dc0b6994b583d40a05d0808a5cb193641d220 + languageName: node + linkType: hard + +"cli-spinners@npm:^2.9.2": + version: 2.9.2 + resolution: "cli-spinners@npm:2.9.2" + checksum: 10c0/907a1c227ddf0d7a101e7ab8b300affc742ead4b4ebe920a5bf1bc6d45dce2958fcd195eb28fa25275062fe6fa9b109b93b63bc8033396ed3bcb50297008b3a3 + languageName: node + linkType: hard + "cliui@npm:^8.0.1": version: 8.0.1 resolution: "cliui@npm:8.0.1" @@ -2622,6 +2868,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^12.0.0": + version: 12.1.0 + resolution: "commander@npm:12.1.0" + checksum: 10c0/6e1996680c083b3b897bfc1cfe1c58dfbcd9842fd43e1aaf8a795fbc237f65efcc860a3ef457b318e73f29a4f4a28f6403c3d653d021d960e4632dd45bde54a9 + languageName: node + linkType: hard + "commander@npm:^2.20.0": version: 2.20.3 resolution: "commander@npm:2.20.3" @@ -2911,6 +3164,13 @@ __metadata: languageName: node linkType: hard +"diff@npm:^8.0.2": + version: 8.0.2 + resolution: "diff@npm:8.0.2" + checksum: 10c0/abfb387f033e089df3ec3be960205d17b54df8abf0924d982a7ced3a94c557a4e6cbff2e78b121f216b85f466b3d8d041673a386177c311aaea41459286cc9bc + languageName: node + linkType: hard + "doctrine@npm:^2.1.0": version: 2.1.0 resolution: "doctrine@npm:2.1.0" @@ -2966,6 +3226,13 @@ __metadata: languageName: node linkType: hard +"emoji-regex@npm:^10.3.0": + version: 10.6.0 + resolution: "emoji-regex@npm:10.6.0" + checksum: 10c0/1e4aa097bb007301c3b4b1913879ae27327fdc48e93eeefefe3b87e495eb33c5af155300be951b4349ff6ac084f4403dc9eff970acba7c1c572d89396a9a32d7 + languageName: node + linkType: hard + "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -3226,6 +3493,95 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:~0.27.0": + version: 0.27.2 + resolution: "esbuild@npm:0.27.2" + dependencies: + "@esbuild/aix-ppc64": "npm:0.27.2" + "@esbuild/android-arm": "npm:0.27.2" + "@esbuild/android-arm64": "npm:0.27.2" + "@esbuild/android-x64": "npm:0.27.2" + "@esbuild/darwin-arm64": "npm:0.27.2" + "@esbuild/darwin-x64": "npm:0.27.2" + "@esbuild/freebsd-arm64": "npm:0.27.2" + "@esbuild/freebsd-x64": "npm:0.27.2" + "@esbuild/linux-arm": "npm:0.27.2" + "@esbuild/linux-arm64": "npm:0.27.2" + "@esbuild/linux-ia32": "npm:0.27.2" + "@esbuild/linux-loong64": "npm:0.27.2" + "@esbuild/linux-mips64el": "npm:0.27.2" + "@esbuild/linux-ppc64": "npm:0.27.2" + "@esbuild/linux-riscv64": "npm:0.27.2" + "@esbuild/linux-s390x": "npm:0.27.2" + "@esbuild/linux-x64": "npm:0.27.2" + "@esbuild/netbsd-arm64": "npm:0.27.2" + "@esbuild/netbsd-x64": "npm:0.27.2" + "@esbuild/openbsd-arm64": "npm:0.27.2" + "@esbuild/openbsd-x64": "npm:0.27.2" + "@esbuild/openharmony-arm64": "npm:0.27.2" + "@esbuild/sunos-x64": "npm:0.27.2" + "@esbuild/win32-arm64": "npm:0.27.2" + "@esbuild/win32-ia32": "npm:0.27.2" + "@esbuild/win32-x64": "npm:0.27.2" + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/openharmony-arm64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 10c0/cf83f626f55500f521d5fe7f4bc5871bec240d3deb2a01fbd379edc43b3664d1167428738a5aad8794b35d1cca985c44c375b1cd38a2ca613c77ced2c83aafcd + languageName: node + linkType: hard + "escalade@npm:^3.1.1, escalade@npm:^3.2.0": version: 3.2.0 resolution: "escalade@npm:3.2.0" @@ -3517,6 +3873,15 @@ __metadata: languageName: node linkType: hard +"fast-check@npm:^4.3.0": + version: 4.3.0 + resolution: "fast-check@npm:4.3.0" + dependencies: + pure-rand: "npm:^7.0.0" + checksum: 10c0/91d73395d6a7523f94514c9c2bda7452c506e73f9d68e77eb45cc83c525c9cc01c5b4331cc18607219f0327ab2dc83963e45c9216e7fd6d85b49b871b4ea2033 + languageName: node + linkType: hard + "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -3851,6 +4216,13 @@ __metadata: languageName: node linkType: hard +"get-east-asian-width@npm:^1.0.0": + version: 1.4.0 + resolution: "get-east-asian-width@npm:1.4.0" + checksum: 10c0/4e481d418e5a32061c36fbb90d1b225a254cc5b2df5f0b25da215dcd335a3c111f0c2023ffda43140727a9cafb62dac41d022da82c08f31083ee89f714ee3b83 + languageName: node + linkType: hard + "get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0": version: 1.3.0 resolution: "get-intrinsic@npm:1.3.0" @@ -4353,6 +4725,13 @@ __metadata: languageName: node linkType: hard +"is-interactive@npm:^2.0.0": + version: 2.0.0 + resolution: "is-interactive@npm:2.0.0" + checksum: 10c0/801c8f6064f85199dc6bf99b5dd98db3282e930c3bc197b32f2c5b89313bb578a07d1b8a01365c4348c2927229234f3681eb861b9c2c92bee72ff397390fa600 + languageName: node + linkType: hard + "is-map@npm:^2.0.3": version: 2.0.3 resolution: "is-map@npm:2.0.3" @@ -4442,6 +4821,20 @@ __metadata: languageName: node linkType: hard +"is-unicode-supported@npm:^1.3.0": + version: 1.3.0 + resolution: "is-unicode-supported@npm:1.3.0" + checksum: 10c0/b8674ea95d869f6faabddc6a484767207058b91aea0250803cbf1221345cb0c56f466d4ecea375dc77f6633d248d33c47bd296fb8f4cdba0b4edba8917e83d8a + languageName: node + linkType: hard + +"is-unicode-supported@npm:^2.0.0": + version: 2.1.0 + resolution: "is-unicode-supported@npm:2.1.0" + checksum: 10c0/a0f53e9a7c1fdbcf2d2ef6e40d4736fdffff1c9f8944c75e15425118ff3610172c87bf7bc6c34d3903b04be59790bb2212ddbe21ee65b5a97030fc50370545a5 + languageName: node + linkType: hard + "is-weakmap@npm:^2.0.2": version: 2.0.2 resolution: "is-weakmap@npm:2.0.2" @@ -4668,6 +5061,16 @@ __metadata: languageName: node linkType: hard +"log-symbols@npm:^6.0.0": + version: 6.0.0 + resolution: "log-symbols@npm:6.0.0" + dependencies: + chalk: "npm:^5.3.0" + is-unicode-supported: "npm:^1.3.0" + checksum: 10c0/36636cacedba8f067d2deb4aad44e91a89d9efb3ead27e1846e7b82c9a10ea2e3a7bd6ce28a7ca616bebc60954ff25c67b0f92d20a6a746bb3cc52c3701891f6 + languageName: node + linkType: hard + "loose-envify@npm:^1.1.0, loose-envify@npm:^1.4.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" @@ -4825,6 +5228,13 @@ __metadata: languageName: node linkType: hard +"mimic-function@npm:^5.0.0": + version: 5.0.1 + resolution: "mimic-function@npm:5.0.1" + checksum: 10c0/f3d9464dd1816ecf6bdf2aec6ba32c0728022039d992f178237d8e289b48764fee4131319e72eedd4f7f094e22ded0af836c3187a7edc4595d28dd74368fd81d + languageName: node + linkType: hard + "min-indent@npm:^1.0.0": version: 1.0.1 resolution: "min-indent@npm:1.0.1" @@ -5174,6 +5584,15 @@ __metadata: languageName: node linkType: hard +"onetime@npm:^7.0.0": + version: 7.0.0 + resolution: "onetime@npm:7.0.0" + dependencies: + mimic-function: "npm:^5.0.0" + checksum: 10c0/5cb9179d74b63f52a196a2e7037ba2b9a893245a5532d3f44360012005c9cadb60851d56716ebff18a6f47129dab7168022445df47c2aff3b276d92585ed1221 + languageName: node + linkType: hard + "openai@npm:^4.95.1": version: 4.95.1 resolution: "openai@npm:4.95.1" @@ -5213,6 +5632,23 @@ __metadata: languageName: node linkType: hard +"ora@npm:^8.0.1": + version: 8.2.0 + resolution: "ora@npm:8.2.0" + dependencies: + chalk: "npm:^5.3.0" + cli-cursor: "npm:^5.0.0" + cli-spinners: "npm:^2.9.2" + is-interactive: "npm:^2.0.0" + is-unicode-supported: "npm:^2.0.0" + log-symbols: "npm:^6.0.0" + stdin-discarder: "npm:^0.2.2" + string-width: "npm:^7.2.0" + strip-ansi: "npm:^7.1.0" + checksum: 10c0/7d9291255db22e293ea164f520b6042a3e906576ab06c9cf408bf9ef5664ba0a9f3bd258baa4ada058cfcc2163ef9b6696d51237a866682ce33295349ba02c3a + languageName: node + linkType: hard + "own-keys@npm:^1.0.1": version: 1.0.1 resolution: "own-keys@npm:1.0.1" @@ -5371,6 +5807,27 @@ __metadata: languageName: node linkType: hard +"pocketbase-zod-schema@npm:^0.2.1": + version: 0.2.1 + resolution: "pocketbase-zod-schema@npm:0.2.1" + dependencies: + chalk: "npm:^5.3.0" + commander: "npm:^12.0.0" + ora: "npm:^8.0.1" + pocketbase: "npm:^0.26.0" + tsx: "npm:^4.19.2" + zod: "npm:^3.24.3" + peerDependencies: + zod: ^3.20.0 + peerDependenciesMeta: + zod: + optional: false + bin: + pocketbase-migrate: dist/cli/migrate.js + checksum: 10c0/54d84815eba6b43efcbbcd2c2cbc3e821da2e9b8a4e9b871cdb1846c8b919d76edcbbbaaeb107af728b83028405c285d20bd371698641f30591f307c44204fed + languageName: node + linkType: hard + "pocketbase@npm:^0.26.0": version: 0.26.0 resolution: "pocketbase@npm:0.26.0" @@ -5512,6 +5969,13 @@ __metadata: languageName: node linkType: hard +"pure-rand@npm:^7.0.0": + version: 7.0.1 + resolution: "pure-rand@npm:7.0.1" + checksum: 10c0/9cade41030f5ec95f5d55a11a71404cd6f46b69becaad892097cd7f58e2c6248cd0a933349ca7d21336ab629f1da42ffe899699b671bc4651600eaf6e57f837e + languageName: node + linkType: hard + "qs@npm:^6.11.0, qs@npm:^6.14.0": version: 6.14.0 resolution: "qs@npm:6.14.0" @@ -5828,6 +6292,16 @@ __metadata: languageName: node linkType: hard +"restore-cursor@npm:^5.0.0": + version: 5.1.0 + resolution: "restore-cursor@npm:5.1.0" + dependencies: + onetime: "npm:^7.0.0" + signal-exit: "npm:^4.1.0" + checksum: 10c0/c2ba89131eea791d1b25205bdfdc86699767e2b88dee2a590b1a6caa51737deac8bad0260a5ded2f7c074b7db2f3a626bcf1fcf3cdf35974cbeea5e2e6764f60 + languageName: node + linkType: hard + "retry@npm:^0.12.0": version: 0.12.0 resolution: "retry@npm:0.12.0" @@ -6334,7 +6808,7 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^4.0.1": +"signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83 @@ -6455,6 +6929,13 @@ __metadata: languageName: node linkType: hard +"stdin-discarder@npm:^0.2.2": + version: 0.2.2 + resolution: "stdin-discarder@npm:0.2.2" + checksum: 10c0/c78375e82e956d7a64be6e63c809c7f058f5303efcaf62ea48350af072bacdb99c06cba39209b45a071c1acbd49116af30df1df9abb448df78a6005b72f10537 + languageName: node + linkType: hard + "string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" @@ -6477,6 +6958,17 @@ __metadata: languageName: node linkType: hard +"string-width@npm:^7.2.0": + version: 7.2.0 + resolution: "string-width@npm:7.2.0" + dependencies: + emoji-regex: "npm:^10.3.0" + get-east-asian-width: "npm:^1.0.0" + strip-ansi: "npm:^7.1.0" + checksum: 10c0/eb0430dd43f3199c7a46dcbf7a0b34539c76fe3aa62763d0b0655acdcbdf360b3f66f3d58ca25ba0205f42ea3491fa00f09426d3b7d3040e506878fc7664c9b9 + languageName: node + linkType: hard + "string.prototype.trim@npm:^1.2.10": version: 1.2.10 resolution: "string.prototype.trim@npm:1.2.10" @@ -6533,6 +7025,15 @@ __metadata: languageName: node linkType: hard +"strip-ansi@npm:^7.1.0": + version: 7.1.2 + resolution: "strip-ansi@npm:7.1.2" + dependencies: + ansi-regex: "npm:^6.0.1" + checksum: 10c0/0d6d7a023de33368fd042aab0bf48f4f4077abdfd60e5393e73c7c411e85e1b3a83507c11af2e656188511475776215df9ca589b4da2295c9455cc399ce1858b + languageName: node + linkType: hard + "strip-bom@npm:^3.0.0": version: 3.0.0 resolution: "strip-bom@npm:3.0.0" @@ -6897,6 +7398,22 @@ __metadata: languageName: node linkType: hard +"tsx@npm:^4.19.2": + version: 4.21.0 + resolution: "tsx@npm:4.21.0" + dependencies: + esbuild: "npm:~0.27.0" + fsevents: "npm:~2.3.3" + get-tsconfig: "npm:^4.7.5" + dependenciesMeta: + fsevents: + optional: true + bin: + tsx: dist/cli.mjs + checksum: 10c0/f5072923cd8459a1f9a26df87823a2ab5754641739d69df2a20b415f61814322b751fa6be85db7c6ec73cf68ba8fac2fd1cfc76bdb0aa86ded984d84d5d2126b + languageName: node + linkType: hard + "tsx@npm:^4.19.3": version: 4.19.3 resolution: "tsx@npm:4.19.3"