diff --git a/docs/INDEX.md b/docs/INDEX.md index 23a8d89..a6177b6 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -76,16 +76,16 @@ imports are resolved at compile time by the SDK. ### KvStoreInstance Methods -| Method | Signature | Description | -| ---------------------- | --------------------------------------------------------------------------------- | ----------------------------------------------------- | -| `get` | `(key: string): ArrayBuffer \| null` | Retrieve a value by key | -| `getEntry` | `(key: string): Promise` | Retrieve a value as a `KvStoreEntry` | -| `scan` | `(pattern: string): Array` | Retrieve keys matching a prefix pattern (e.g. `foo*`) | -| `zrangeByScore` | `(key: string, min: number, max: number): Array<[ArrayBuffer, number]>` | Retrieve sorted set entries by score range | -| `zrangeByScoreEntries` | `(key: string, min: number, max: number): Promise>` | `zrangeByScore` returning `KvStoreEntry` wrappers | -| `zscan` | `(key: string, pattern: string): Array<[ArrayBuffer, number]>` | Retrieve sorted set entries matching a prefix pattern | -| `zscanEntries` | `(key: string, pattern: string): Promise>` | `zscan` returning `KvStoreEntry` wrappers | -| `bfExists` | `(key: string, value: string): boolean` | Check if a value exists in a Bloom Filter | +| Method | Signature | Description | +| ---------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------ | +| `get` | `(key: string): ArrayBuffer \| null` | Retrieve a value by key | +| `getEntry` | `(key: string): Promise` | Retrieve a value as a `KvStoreEntry` | +| `scan` | `(pattern: string): Array` | Retrieve keys matching a prefix pattern (e.g. `foo*`) | +| `zrangeByScore` | `(key: string, min: number, max: number): Array<[ArrayBuffer, number]>` | Retrieve sorted set entries by score range | +| `zrangeByScoreEntries` | `(key: string, min: number, max: number): Promise>` | `zrangeByScore` returning `KvStoreEntry` wrappers | +| `zscan` | `(key: string, pattern: string): Array<[ArrayBuffer, number]>` | Retrieve sorted set entries matching a prefix pattern | +| `zscanEntries` | `(key: string, pattern: string): Promise>` | `zscan` returning `KvStoreEntry` wrappers | +| `bfExists` | `(key: string, value: string): boolean` | Check if a value exists in a Bloom Filter | ### KvStoreEntry Methods @@ -127,19 +127,19 @@ async function app(event) { addEventListener('fetch', (event) => event.respondWith(app(event))); ``` -| Method | Signature | Description | -| ------------ | --------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | -| `get` | `(key: string): Promise` | Get entry or `null` if absent or expired | -| `exists` | `(key: string): Promise` | Check key presence without transferring value | -| `set` | `(key: string, value: CacheValue, options?: WriteOptions): Promise` | Store a value, optionally with expiry | -| `delete` | `(key: string): Promise` | Remove a key; no-op if absent | -| `expire` | `(key: string, options: WriteOptions): Promise` | Update expiry; `true` if key exists, `false` if not | -| `incr` | `(key: string, delta?: number): Promise` | Atomically increment an integer; returns new value | -| `decr` | `(key: string, delta?: number): Promise` | Atomically decrement an integer; returns new value | -| `getOrSet` | `(key: string, populate: () => CacheValue \| Promise, options?: WriteOptions): Promise` | Get entry or populate, cache, and return the result | -| `getOrSet` | `(key: string, populate: () => CacheValue \| null \| Promise, options?: WriteOptions): Promise` | As above; a `null` populator result skips the write and resolves with `null` | -| `purge` | `(): Promise` | Delete all cache entries for this application; returns count deleted | -| `purgePrefix` | `(prefix: string): Promise` | Delete all entries whose keys begin with `prefix`; returns count deleted | +| Method | Signature | Description | +| ------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | +| `get` | `(key: string): Promise` | Get entry or `null` if absent or expired | +| `exists` | `(key: string): Promise` | Check key presence without transferring value | +| `set` | `(key: string, value: CacheValue, options?: WriteOptions): Promise` | Store a value, optionally with expiry | +| `delete` | `(key: string): Promise` | Remove a key; no-op if absent | +| `expire` | `(key: string, options: WriteOptions): Promise` | Update expiry; `true` if key exists, `false` if not | +| `incr` | `(key: string, delta?: number): Promise` | Atomically increment an integer; returns new value | +| `decr` | `(key: string, delta?: number): Promise` | Atomically decrement an integer; returns new value | +| `getOrSet` | `(key: string, populate: () => CacheValue \| Promise, options?: WriteOptions): Promise` | Get entry or populate, cache, and return the result | +| `getOrSet` | `(key: string, populate: () => CacheValue \| null \| Promise, options?: WriteOptions): Promise` | As above; a `null` populator result skips the write and resolves with `null` | +| `purge` | `(): Promise` | Delete all cache entries for this application; returns count deleted | +| `purgePrefix` | `(prefix: string): Promise` | Delete all entries whose keys begin with `prefix`; returns count deleted | ### CacheValue diff --git a/docs/quickstart.md b/docs/quickstart.md index c31d6f2..c0d3696 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -58,6 +58,33 @@ npx fastedge-build --input src/index.ts --output app.wasm --tsconfig tsconfig.js | `--version` | `-v` | `boolean` | Print version | | `--help` | `-h` | `boolean` | Print help | +## TypeScript Configuration + +If you're using TypeScript, use a `tsconfig.json` that works with `fastedge-build`'s esbuild-based compilation pipeline. The following is the canonical template: + +```json +{ + "compilerOptions": { + "target": "ES2023", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "skipLibCheck": true, + "noEmit": true, + "lib": ["ES2023"], + "types": ["@gcoredev/fastedge-sdk-js"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] +} +``` + +Three settings require explanation: + +- **`moduleResolution: "Bundler"`** — Required. `fastedge-build` uses esbuild to resolve modules, not Node's resolution algorithm. The `node`, `node16`, and `nodenext` modes are incorrect for FastEdge apps and will produce spurious import errors. +- **`types: ["@gcoredev/fastedge-sdk-js"]`** — Brings `FetchEvent` and all FastEdge globals into scope automatically. No triple-slash directive (`/// `) is needed in TypeScript source files when this field is set. +- **`noEmit: true`** — `tsc` is used for type-checking only. `fastedge-build` handles the actual compilation to WebAssembly; emitting JavaScript from `tsc` would be redundant and incorrect. + ## Write Your First App Create `src/index.js`: @@ -91,7 +118,6 @@ The output `app.wasm` is a WebAssembly component ready for deployment on the Fas `getEnv` is only available during request processing, not at build-time initialization. ```js -/// import { getEnv } from 'fastedge::env'; addEventListener('fetch', (event) => { @@ -116,7 +142,6 @@ Returns `null` when the environment variable is not set. `getSecret` and `getSecretEffectiveAt` are only available during request processing, not at build-time initialization. ```js -/// import { getSecret } from 'fastedge::secret'; addEventListener('fetch', (event) => { @@ -140,7 +165,6 @@ Both return `null` when the secret is not set. ## Using KV Store ```js -/// import { KvStore } from 'fastedge::kv'; addEventListener('fetch', (event) => { @@ -182,7 +206,6 @@ addEventListener('fetch', (event) => { The `fastedge::cache` module provides a POP-local key/value store with TTL and atomic counter primitives. Unlike `fastedge::kv`, which is globally replicated across all data centers, the cache is strongly consistent within a single point of presence and invisible to other POPs — making it suited for request-time state such as rate limiting, hit counters, and response memoisation where low latency within a POP matters more than global durability. ```js -/// import { Cache } from 'fastedge::cache'; addEventListener('fetch', (event) => { diff --git a/fastedge-plugin-source/.generation-config.md b/fastedge-plugin-source/.generation-config.md index a4eaa9a..25fccf1 100644 --- a/fastedge-plugin-source/.generation-config.md +++ b/fastedge-plugin-source/.generation-config.md @@ -80,13 +80,22 @@ files:** `package.json`, `README.md` **Required content:** ## docs/quickstart.md **Scope:** First-time setup — install, scaffold, build, deploy **Source files:** `package.json`, -`README.md`, `src/cli/fastedge-init/init.ts`, `src/cli/fastedge-build/build.ts` **Required -content:** +`README.md`, `src/cli/fastedge-init/init.ts`, `src/cli/fastedge-build/build.ts`, +`examples/cache/tsconfig.json` **Required content:** - Prerequisites — read the minimum Node version from `package.json` `engines.node` field (do NOT hardcode a version number) - npm install command - Two paths: scaffold with fastedge-init OR build directly +- **TypeScript Configuration** — a dedicated section explaining the canonical `tsconfig.json` for + FastEdge apps. Include the full JSON block verbatim from `examples/cache/tsconfig.json` (that file + is the authoritative app-level template; do NOT use the repo-root `tsconfig.json`, which is the + SDK's own build config). Briefly explain the three non-obvious settings: `moduleResolution: + "Bundler"` (required — esbuild handles resolution, not Node), `types: + ["@gcoredev/fastedge-sdk-js"]` (brings `FetchEvent` and all FastEdge globals into scope without a + triple-slash directive), `noEmit: true` (tsc is used for type-checking only; `fastedge-build` + handles the actual compilation). Note that `node`, `node16`, and `nodenext` moduleResolution modes + are incorrect for FastEdge apps and will produce spurious errors. - Complete "first app" example with env vars, secrets, and KV store - Short "Using Cache" section after "Using KV Store" — one paragraph contrasting POP-local Cache vs globally-replicated KV, plus a minimal example covering `Cache.get`/`Cache.set` (or diff --git a/fastedge-plugin-source/generate-docs.sh b/fastedge-plugin-source/generate-docs.sh index f6d4f2c..c7d99e7 100755 --- a/fastedge-plugin-source/generate-docs.sh +++ b/fastedge-plugin-source/generate-docs.sh @@ -88,7 +88,7 @@ ALL_FILES=("${TIER1_FILES[@]}" "${TIER2_FILES[@]}" "${TIER3_FILES[@]}") declare -A SOURCE_FILES SOURCE_FILES[INDEX.md]="package.json README.md docs/SDK_API.md" -SOURCE_FILES[quickstart.md]="README.md src/cli/fastedge-init/init.ts src/cli/fastedge-build/build.ts" +SOURCE_FILES[quickstart.md]="README.md src/cli/fastedge-init/init.ts src/cli/fastedge-build/build.ts examples/cache/tsconfig.json" SOURCE_FILES[BUILD_CLI.md]="src/cli/fastedge-build/build.ts src/cli/fastedge-build/types.ts src/cli/fastedge-build/config-build.ts" SOURCE_FILES[INIT_CLI.md]="src/cli/fastedge-init/init.ts src/cli/fastedge-init/http-handler.ts src/cli/fastedge-init/static-site.ts src/cli/fastedge-init/create-config.ts" SOURCE_FILES[ASSETS_CLI.md]="src/cli/fastedge-assets/asset-cli.ts src/server/static-assets/asset-manifest/create-manifest.ts"