Skip to content

Latest commit

Β 

History

154 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

TeaQL-TS (TypeScript Runtime)

Sensitive log data

Runtime diagnostic logs redact payload values by default, before delivery to file, console, buffers, or custom logging sinks. Selecting a diagnostic sink alone does not authorize plaintext. For controlled troubleshooting only:

export TEAQL_ALLOW_SENSITIVE_PLAINTEXT_LOGS=I_UNDERSTAND_SENSITIVE_DATA_MAY_BE_WRITTEN_TO_DISK

Only this exact value enables plaintext permission; empty values, true, and whitespace variants do not. Enabling it emits a warning. Credential-classified fields remain redacted. The flag does not force every sink to expose values. SQL without reliable field/literal provenance may be suppressed and marked NOT REPLAYABLE. Execution parameters and persisted business data are unchanged.

Do not put sensitive data in free-text comments or purpose declarations. TeaQL cannot govern arbitrary application prints or independent driver loggers; configure those separately. This setting does not erase older plaintext files. Restrict access and retention when using plaintext diagnostics, then unset the variable and restart processes when troubleshooting is complete.

teaql-ts is the core TypeScript runtime framework for the TEAQL Federation Protocol (TFP). It provides an ultra-lightweight engine responsible for securely translating elegant chained DSLs into cross-language ASTs, allowing you to enjoy a strongly-typed, highly expressive data fetching experience on the frontend (or Node.js).

Recommended Agent Harness

When building database-backed or federated applications with the TeaQL TypeScript runtime, we recommend using it together with the TeaQL Agent Kit. The Agent Kit is TeaQL's continuously evolving Harness Engineering method. It gives coding agents a model-mediated, executable workflow for domain modeling, deterministic evaluation and repair, code generation, implementation, and evidence-based verification as the generator and runtimes evolve.

Runtime Profiles

teaql-ts uses explicit package entry points as runtime profiles. Import only the profile needed by the application:

Profile Import Runtime Database driver
Browser / TFP teaql-ts Browser or Node HTTP client None
PostgreSQL teaql-ts/sql/postgres Node.js pg
MySQL teaql-ts/sql/mysql Node.js mysql2
SQLite teaql-ts/sql/sqlite Node.js better-sqlite3
Expo SQLite teaql-ts/sql/expo-sqlite React Native / Expo expo-sqlite
Browser SQLite teaql-ts/sql/browser-sqlite Browser Web Worker @sqlite.org/sqlite-wasm

Security Boundary

The browser/TFP profile is a client, not a key-custody service. It produces a controlled AST and sends declared comment/purpose to a trusted TeaQL backend; it cannot override server tenant, role, field, hard-limit, or optimistic-lock policy. Browser SQLite is local application storage and does not turn the browser into a public TFP server.

When a Java, Rust, Go, or .NET backend returns a TeaQL opaque entity reference, TypeScript treats it as an indivisible string and returns it only for the operation and purpose for which it was issued. Client code must not parse, rewrite, log, or manufacture the token, and must not fall back to exposing a raw internal ID/version pair. The current TypeScript profile deliberately does not hold backend AES keys or provide local encode/decode APIs; this is a supported frontend boundary rather than a conformance defect.

Local SQL logging should remain parameterized and value-free by default. Copy/paste SQL or submitted values belong only in an explicit, access-controlled diagnostic surface. The server-side envelope, golden vector, stable errors, and development-only raw-reference acknowledgement are defined in the canonical opaque entity reference contract.

Mutation Policy installation

All profiles support the same application-owned Mutation Policy identity, approval, warning, and evidence contract. Node SQL and browser SQLite review a complete generated graph after Checker/Fix and before the first provider mutation. The TFP browser/Node client applies the policy before fetch as defense in depth; the receiving server still performs the authoritative review.

const context = new UserContext()
  .withMutationPolicyRegistry(policyRegistry)
  .withMutationPolicyApprovalProvider(approvalProvider)
  .withMutationGovernanceSink(warningSink);

client.setUserContext(context);

A customer policy denial reaches neither SQL, the browser SQLite worker, nor a TFP mutation request. Missing customer policy or exact approval uses stable warning codes and remains fail-open, while explicit denial and incomplete graph plans fail closed. Policy implementations are installed only through trusted context assembly and are never accepted from JSON or TFP payloads.

Browser / TFP profile

The default entry point contains the AST, Peggy-generated controlled query parser, and TFP HTTP client. It does not import or bundle PostgreSQL, MySQL, or SQLite drivers.

npm install teaql-ts
import { SelectQuery, TeaQLClient } from "teaql-ts";

const client = new TeaQLClient({ baseUrl: "/api/teaql" });
const tasks = await client.executeQuery(
  new SelectQuery("Task")
    .comment("task board initial load")
    .limit(20)
    .purpose("show current tasks"),
);

Database drivers are optional peer dependencies. A browser application should import only from teaql-ts and should not install a SQL driver package.

Node SQL profiles

Install only the driver selected by the service:

# PostgreSQL
npm install teaql-ts pg

# MySQL
npm install teaql-ts mysql2

# SQLite
npm install teaql-ts better-sqlite3

Use the matching subpath when building a runtime manually. ENTITY_SCHEMAS is normally generated by teaql-code-gen:

import { PostgreSQLTeaQLClient } from "teaql-ts/sql/postgres";
import { ENTITY_SCHEMAS } from "./teaql-node-sql";

const client = new PostgreSQLTeaQLClient(
  process.env.DATABASE_URL!,
  ENTITY_SCHEMAS,
);
const ctx = { client };

The MySQL and SQLite forms are identical apart from the selected profile:

import { MySQLTeaQLClient } from "teaql-ts/sql/mysql";
import { SQLiteTeaQLClient } from "teaql-ts/sql/sqlite";

Generated Node projects wrap these classes in teaql-node-postgres.ts, teaql-node-mysql.ts, or teaql-node-sqlite.ts, so application code normally imports the generated wrapper and does not pass ENTITY_SCHEMAS itself.

In a TeaQL model, data_service="postgres", data_service="mysql", or data_service="sqlite" selects the corresponding generated SQL profile. The regular TypeScript/browser generation profile continues to use TFP and has no database-driver import.

React Native / Expo SQLite profile

Generated typescript-app-expo workspaces open and ensure their local schema on first launch, so a new user does not need to download or prepare a database file. The generated schema remains the source of truth:

import * as SQLite from "expo-sqlite";
import { ExpoSQLiteTeaQLClient } from "teaql-ts/sql/expo-sqlite";
import { ENTITY_SCHEMAS } from "./teaql-expo-sql";

const database = await SQLite.openDatabaseAsync("order-management.db");
const client = new ExpoSQLiteTeaQLClient(database, ENTITY_SCHEMAS);

Local queries still require comment(...) and purpose(...), and saves still require an audit reason. The same generated model can instead use the default TFP client for authenticated server queries. Tenant, user, permission, purpose policy, hard-limit policy, and continuous-page cursor policy must be supplied by trusted runtime context; they are not accepted from federation JSON.

Browser SQLite/WASM profile

Browser-local applications can execute the same generated Q API, E API, Checker/Fix rules, audited mutations, and Runtime Module bootstrap without a backend. Install the official SQLite/WASM package and create an application-owned worker entry point so bundlers can package the worker and WASM assets correctly:

npm install teaql-ts @sqlite.org/sqlite-wasm
import sqliteWasmUrl from "@sqlite.org/sqlite-wasm/sqlite3.wasm?url";
import { startBrowserSQLiteWorker } from "teaql-ts/sql/browser-sqlite-worker";

startBrowserSQLiteWorker({ wasmUrl: sqliteWasmUrl });
import { BrowserSQLiteTeaQLClient } from "teaql-ts/sql/browser-sqlite";

const worker = new Worker(new URL("./sqlite.worker.ts", import.meta.url), {
  type: "module",
});
const client = await BrowserSQLiteTeaQLClient.open(worker, ENTITY_SCHEMAS, {
  storage: "memory", // deterministic default; use "opfs" only by explicit choice
});
client.install(GENERATED_RUNTIME_MODULE);
const context = new UserContext().insertResource("dataService", client);
client.setUserContext(context);
await context.ensureSchema();

client.reset(context) drops browser-local tables, explicitly reconciles the schema again, and runs the generated mutation bootstrap. OPFS requires the COOP/COEP headers documented by SQLite. The first browser profile deliberately buffers stream results and does not promise multi-tab database coordination. It is intended for Playground, offline, and local-data scenariosβ€”not as a trusted authorization boundary for tenant or permission enforcement.

See examples/browser-sqlite for the executable memory, OPFS, Mutation Policy, generated-mutation seed, Q API, and reset verification.

🌟 Why Will It Make You Say "Wow"?

Take a look at this code driven by teaql-ts, and you will feel the beauty of perfectly combining type safety with declarative expression. You no longer need to manually concatenate GraphQL strings or deal with tedious RESTful parameters, just write this:

The Ultimate Elegance for Pro Code (Native)

If you are a full-stack developer, after having the generated Q Builder, you can write extremely smooth chained code, and the IDE will provide you with 100% intelligent auto-completion:

// Business Requirement: Fetch all current tasks, and attach a "statistics panel" (Facet) to count them by status
const result = await Q.tasks()
  .withNameContaining("bug")
  .facetByStatusAs("statusFacet", Q.taskStatuses().count())
  .purpose("find bugs")
  .executeForList(ctx);

// Returns highly integrated JSON, a single response containing both main data and the statistics panel
console.log("Main Data (Tasks):", result.data);
console.log("Statistics Panel (Facets):", result.facets);

Data Mutations and Updates (Mutations)

TeaQL TS also natively supports strongly-typed data creation and updates:

import { Task } from './generated/models/Task';

// Create a new Task
const newTask = new Task({ 
    name: "New feature implementation", 
    status: 1001 
});
const createResult = await newTask.auditAs("Create new feature ticket").save(ctx);
const newVersion = createResult.data[0].saved_data.version;

// Update a Task
const updateTask = new Task({ 
    id: 9527, 
    version: newVersion, // Optimistic Concurrency Control requires version
    name: "New feature implementation (Updated)", 
    status: 1002 
});
const updateResult = await updateTask.auditAs("Move to ready").save(ctx);
const updatedVersion = updateResult.data[0].saved_data.version;

// Delete a Task
const taskToDelete = new Task({ id: 9527, version: updatedVersion });
const deleteResult = await taskToDelete.markForDeletion().auditAs("Delete obsolete task").save(ctx);

The Ultimate Safety for Low Code (Dynamic)

If you are building a "No-Code Platform" or "Dynamic Reporting", you can pass the above code directly as a raw string from the webpage to the interpreter. It will execute perfectly without any risk of eval() injection:

// Raw string received from a frontend input box
const userQuery = 'Q.tasks().withNameContaining("bug").facetByStatusAs("statusFacet", Q.taskStatuses().count())';

// Securely parse the complete source into a controlled AST, then invoke only
// methods exposed by the generated Q entry point. No eval/new Function is used.
const request = QueryParser.parse(userQuery, Q);
const result = await request.executeForList(ctx);

πŸ“‚ Project Architecture and Domain Examples

Architecturally, teaql-ts adheres to the philosophy of absolute isolation between the Framework Layer and the Business Layer. The src directory in this repository is the pure, uncontaminated core engine, while all practical business demonstrations are divided by domain in the examples directory.

teaql-ts/
β”œβ”€β”€ src/                      # [Framework Layer] Pure core engine, no business code
β”‚   β”œβ”€β”€ core/                 # AST definitions
β”‚   β”œβ”€β”€ parser/               # DSL reflection and secure interpreter
β”‚   β”œβ”€β”€ tfp/                  # Federation network transport protocol layer
β”‚   └── sql/                  # Node-only SQL profiles, available through explicit subpaths
β”‚
└── examples/                 # [Business Example Layer] Integrated demos for various use cases
    β”‚
    β”œβ”€β”€ task-board/           # Example 1: Task Board System Domain
    β”‚   β”œβ”€β”€ ts-lib-core/      # Strongly-typed domain models generated by the code generator (e.g. Task, Q.ts)
    β”‚   β”œβ”€β”€ app-dynamic/      # Runtime Demo based on dynamic string parsing
    β”‚   └── app-native/       # Demo based on fluent hardcoded API
    β”‚
    └── ecommerce-system/     # Example 2: [Planned] E-commerce System Example

Releases

Packages

Contributors

Languages