From 7213e634ce48f15c65126866b3aa91baf9d3f2b5 Mon Sep 17 00:00:00 2001 From: "fastedge-plugin-sync[bot]" Date: Fri, 2 Oct 2026 09:17:24 +0000 Subject: [PATCH] auto: update reference docs from fastedge-sdk-js (v2.5.2) --- .../reference/http/examples-ab-testing-js.md | 6 +- .../reference/http/examples-auth-js.md | 4 +- .../reference/http/examples-cache-js.md | 8 +- .../reference/http/examples-fetch-js.md | 6 +- .../http/examples-geo-redirect-js.md | 6 +- .../reference/http/examples-headers-js.md | 8 +- .../reference/http/examples-hono-js.md | 4 +- .../reference/http/examples-kv-store-js.md | 8 +- .../reference/http/examples-proxy-js.md | 6 +- .../fastedge-docs/reference/js-runtime.md | 4 +- .../fastedge-docs/reference/quickstart-js.md | 4 +- .../reference/sdk-reference-js.md | 4 +- .../skills/scaffold/reference/build-cli.md | 4 +- .../scaffold/reference/http/ab-testing-ts.md | 8 +- .../skills/scaffold/reference/http/base-ts.md | 8 +- .../http/bloom-filter-denylist-ts.md | 70 +--- .../scaffold/reference/http/cache-basic-ts.md | 122 +------ .../scaffold/reference/http/cache-ts.md | 284 +-------------- .../reference/http/crypto-hmac-jwt-ts.md | 8 +- .../scaffold/reference/http/fetch-ts.md | 8 +- .../reference/http/geo-redirect-ts.md | 8 +- .../scaffold/reference/http/headers-ts.md | 8 +- .../reference/http/kv-store-basic-ts.md | 8 +- .../scaffold/reference/http/kv-store-ts.md | 192 +++++++++- .../scaffold/reference/http/mcp-server-ts.md | 8 +- .../http/outbound-modify-response-ts.md | 54 ++- .../http/react-with-hono-server-ts.md | 8 +- .../reference/http/request-inspection-ts.md | 8 +- .../reference/http/secret-rotation-ts.md | 6 +- .../reference/http/static-assets-ts.md | 339 +++++++++++++++++- .../scaffold/reference/http/streaming-ts.md | 53 ++- .../http/template-invoice-ab-testing-ts.md | 96 ++++- .../reference/http/template-invoice-ts.md | 87 ++++- .../http/variables-and-secrets-ts.md | 8 +- .../skills/scaffold/reference/init-cli.md | 4 +- .../skills/scaffold/reference/static-sites.md | 4 +- 36 files changed, 900 insertions(+), 571 deletions(-) diff --git a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-ab-testing-js.md b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-ab-testing-js.md index 2400018..31c6452 100644 --- a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-ab-testing-js.md +++ b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-ab-testing-js.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> # A/B Testing — FastEdge Example @@ -190,7 +190,7 @@ Iterates each test in `testConfig`, maps `xid * 100` into the normalized variant "build": "fastedge-build src/index.js dist/ab-testing.wasm" }, "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.3.0" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` diff --git a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-auth-js.md b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-auth-js.md index aa6fc7e..a13b00d 100644 --- a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-auth-js.md +++ b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-auth-js.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> # Authentication Patterns (JavaScript) diff --git a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-cache-js.md b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-cache-js.md index 46d3c9c..3c828e9 100644 --- a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-cache-js.md +++ b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-cache-js.md @@ -2,16 +2,16 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> # FastEdge Cache — JavaScript Examples **Module**: `fastedge::cache` **Import**: `import { Cache } from 'fastedge::cache';` -**SDK**: `@gcoredev/fastedge-sdk-js` `^2.3.0` +**SDK**: `@gcoredev/fastedge-sdk-js` `^2.5.2` **App type**: HTTP **Language**: TypeScript / JavaScript @@ -305,7 +305,7 @@ Validation errors (e.g., conflicting `WriteOptions`) are thrown synchronously. H { "type": "module", "scripts": { "build": "fastedge-build -c" }, - "dependencies": { "@gcoredev/fastedge-sdk-js": "^2.3.0" } + "dependencies": { "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` diff --git a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-fetch-js.md b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-fetch-js.md index 7b5cf8c..20ec584 100644 --- a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-fetch-js.md +++ b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-fetch-js.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> ## fetch — Outbound HTTP Requests @@ -55,7 +55,7 @@ addEventListener('fetch', (event) => { | Package | Version | |---------|---------| -| `@gcoredev/fastedge-sdk-js` | `^2.2.2` | +| `@gcoredev/fastedge-sdk-js` | `^2.5.2` | **Build command**: `fastedge-build src/index.js dist/outbound-fetch.wasm` diff --git a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-geo-redirect-js.md b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-geo-redirect-js.md index dad6840..2c5f33e 100644 --- a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-geo-redirect-js.md +++ b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-geo-redirect-js.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> ## Example: Geo-Redirect @@ -23,7 +23,7 @@ Redirects incoming requests to different origins based on the visitor's country, | Package | Version | |---|---| -| `@gcoredev/fastedge-sdk-js` | `^2.3.0` | +| `@gcoredev/fastedge-sdk-js` | `^2.5.2` | --- diff --git a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-headers-js.md b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-headers-js.md index dc5cdf6..db0cb45 100644 --- a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-headers-js.md +++ b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-headers-js.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> ## Headers Example — FastEdge JS @@ -178,11 +178,11 @@ All method names are **case-insensitive** with respect to the header name argume "build": "fastedge-build src/index.js dist/headers.wasm" }, "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.3.0" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` - `"type": "module"` — ES module syntax required (`import`/`export`). - Build output: `dist/headers.wasm` — the binary uploaded to FastEdge. -- SDK version: `@gcoredev/fastedge-sdk-js ^2.3.0`. +- SDK version: `@gcoredev/fastedge-sdk-js ^2.5.2`. diff --git a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-hono-js.md b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-hono-js.md index 61364a2..284bb5b 100644 --- a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-hono-js.md +++ b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-hono-js.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> # Hono Patterns on FastEdge (JavaScript/TypeScript) diff --git a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-kv-store-js.md b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-kv-store-js.md index 76aae72..bf131a6 100644 --- a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-kv-store-js.md +++ b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-kv-store-js.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> ## KV Store — Example Reference @@ -291,7 +291,7 @@ export const stringifyValueScoreTuples = (tupleList: Array<[ArrayBuffer, number] "description": "FastEdge JS example: KV Store operations via query params", "type": "module", "scripts": { "build": "fastedge-build -c" }, - "dependencies": { "@gcoredev/fastedge-sdk-js": "^2.3.0" } + "dependencies": { "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` @@ -326,6 +326,6 @@ TypeScript types for FastEdge globals (`FetchEvent`, etc.) are provided by `@gco - `bfExists` returning `true` is probabilistic (Bloom filter); `false` is definitive. - `min` and `max` for `zrangeByScore` are parsed from query strings with `Number.parseFloat` — ensure numeric string inputs. - `"type": "module"` must be set in `package.json` for ESM compatibility with `fastedge-build`. -- The SDK dependency version is `^2.3.0`. +- The SDK dependency version is `^2.5.2`. - `tsconfig.json` `target` is `ES2023`; `moduleResolution` is `Bundler`; `lib` is `["ES2023"]`; `types` is `["@gcoredev/fastedge-sdk-js"]`. - Empty string values for required query parameters are treated as missing — validation rejects them the same as absent params. diff --git a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-proxy-js.md b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-proxy-js.md index b61ea98..e9b5739 100644 --- a/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-proxy-js.md +++ b/plugins/gcore-fastedge/skills/fastedge-docs/reference/http/examples-proxy-js.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> # Proxy and Response Transform Patterns (JavaScript/TypeScript) @@ -69,7 +69,7 @@ addEventListener("fetch", (event) => { }); ``` -**Gotcha:** `.json()`, `.text()`, and `.arrayBuffer()` are one-shot body consumers — calling any of them exhausts the body stream. You cannot read the body a second time from the same `Response`. If you need the raw bytes and a parsed value, read with `.arrayBuffer()` once, then parse from that buffer. +**Gotcha:** `.json()`, `.text()`, and `.arrayBuffer()` are one-shot body consumers — calling any of them exhausts the body stream. You cannot read the body a second time from the same `Response`. If you need both the raw bytes and a parsed value, read with `.arrayBuffer()` once, then parse from that buffer. --- diff --git a/plugins/gcore-fastedge/skills/fastedge-docs/reference/js-runtime.md b/plugins/gcore-fastedge/skills/fastedge-docs/reference/js-runtime.md index c37305a..6dce0c0 100644 --- a/plugins/gcore-fastedge/skills/fastedge-docs/reference/js-runtime.md +++ b/plugins/gcore-fastedge/skills/fastedge-docs/reference/js-runtime.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> # FastEdge JS Runtime — Constraints & Compatibility diff --git a/plugins/gcore-fastedge/skills/fastedge-docs/reference/quickstart-js.md b/plugins/gcore-fastedge/skills/fastedge-docs/reference/quickstart-js.md index 8bd2b3e..f610d8c 100644 --- a/plugins/gcore-fastedge/skills/fastedge-docs/reference/quickstart-js.md +++ b/plugins/gcore-fastedge/skills/fastedge-docs/reference/quickstart-js.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> # FastEdge JavaScript Quickstart diff --git a/plugins/gcore-fastedge/skills/fastedge-docs/reference/sdk-reference-js.md b/plugins/gcore-fastedge/skills/fastedge-docs/reference/sdk-reference-js.md index e52332f..037f6a1 100644 --- a/plugins/gcore-fastedge/skills/fastedge-docs/reference/sdk-reference-js.md +++ b/plugins/gcore-fastedge/skills/fastedge-docs/reference/sdk-reference-js.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> # JavaScript SDK Reference (`@gcoredev/fastedge-sdk-js`) diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/build-cli.md b/plugins/gcore-fastedge/skills/scaffold/reference/build-cli.md index 7912f54..37e2a72 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/build-cli.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/build-cli.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> ## fastedge-build CLI Reference diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/ab-testing-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/ab-testing-ts.md index 363e4cb..3bb8328 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/ab-testing-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/ab-testing-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -29,7 +29,7 @@ No additional npm dependencies beyond the base skeleton. Uses the `fastedge::env ```json { "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.3.0" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` @@ -366,7 +366,7 @@ const createAbTestHeaders = (reqHeaders, testConfig, xid) => { "build": "fastedge-build src/index.js dist/ab-testing.wasm" }, "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.3.0" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/base-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/base-ts.md index 35e28bd..352d6c9 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/base-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/base-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -14,7 +14,7 @@ languages: [typescript, javascript] template_origin: http-base source_repo: https://github.com/G-Core/FastEdge-sdk-js source_ref: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 -updated: 2026-09-22 +updated: 2026-10-02 --- # Base Skeleton: HTTP TypeScript/JavaScript @@ -186,7 +186,7 @@ addEventListener("fetch", (event) => { "build": "fastedge-build src/index.js dist/hello-world.wasm" }, "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.3.0" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/bloom-filter-denylist-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/bloom-filter-denylist-ts.md index eaa4402..623094f 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/bloom-filter-denylist-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/bloom-filter-denylist-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -160,7 +160,7 @@ Entry point: `src/index.js`. Output: `dist/bloom-filter-denylist.wasm`. Build to **Dependencies:** ```json -"@gcoredev/fastedge-sdk-js": "^2.2.2" +"@gcoredev/fastedge-sdk-js": "^2.5.2" ``` ## False-Positive Trade-off @@ -176,67 +176,3 @@ Bloom filters guarantee no false negatives (an IP absent from the set is never b - fastedge::env reference - fastedge-build CLI reference - KV store setup and bloom-filter payload upload guide - -## Source Material - -### FILE: examples/bloom-filter-denylist/src/index.js - -```js -import { getEnv } from 'fastedge::env'; -import { KvStore } from 'fastedge::kv'; - -const BLOOM_KEY = 'blocked-ips'; - -function app(event) { - const storeName = getEnv('DENYLIST_STORE'); - if (!storeName) { - return Response.json( - { error: 'DENYLIST_STORE environment variable is not configured' }, - { status: 500 }, - ); - } - - const ip = event.client.address; - if (!ip) { - return Response.json({ error: 'client address unavailable' }, { status: 500 }); - } - - let blocked; - try { - const store = KvStore.open(storeName); - blocked = store.bfExists(BLOOM_KEY, ip); - } catch (error) { - return Response.json({ error: `KV lookup failed: ${error.message}` }, { status: 500 }); - } - - if (blocked) { - // Bloom filter says "maybe in set" — a small fraction of hits will be false positives. - // Acceptable for a denylist (you over-block some legitimate users); not acceptable for - // allowlists or anything requiring exact membership — use KvStore.get() for that. - return Response.json({ allowed: false, ip }, { status: 403 }); - } - - return Response.json({ allowed: true, ip }); -} - -addEventListener('fetch', (event) => { - event.respondWith(app(event)); -}); -``` - -### FILE: examples/bloom-filter-denylist/package.json - -```json -{ - "name": "fastedge-example-bloom-filter-denylist", - "version": "1.0.0", - "description": "FastEdge JS example: IP denylist using a KV Store bloom filter", - "type": "module", - "scripts": { - "build": "fastedge-build src/index.js dist/bloom-filter-denylist.wasm" - }, - "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.2.2" - } -} -``` diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/cache-basic-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/cache-basic-ts.md index c10ff23..15dea72 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/cache-basic-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/cache-basic-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -216,14 +216,14 @@ Missing `key` parameter returns HTTP 500 with `{ error: "Missing required query "build": "fastedge-build src/index.js dist/cache-basic.wasm" }, "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.3.0" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` Build command: `fastedge-build src/index.js dist/cache-basic.wasm` -SDK version constraint: `@gcoredev/fastedge-sdk-js ^2.3.0` +SDK version constraint: `@gcoredev/fastedge-sdk-js ^2.5.2` ## See Also @@ -231,117 +231,3 @@ SDK version constraint: `@gcoredev/fastedge-sdk-js ^2.3.0` - fastedge::cache full API reference — advanced patterns, streaming values, CacheEntry interface - http-base skeleton — base HTTP handler structure this feature extends - deploy skill reference — building and uploading the compiled WASM binary - -## Source Material - -### FILE: examples/cache-basic/src/index.js - -```js -// FastEdge Cache — basic operations -// -// The `fastedge::cache` module gives you a fast, data-center-scoped -// key/value store. Values written here are stored in the same point of -// presence (POP) that runs the worker, so reads and writes are very fast, -// and writes from one POP are not visible to others. -// -// Use this for transient, request-time state — short-lived caches, hit -// counters, rate limit windows, deduplicated work. For globally -// replicated storage, use the `fastedge::kv` module instead. -// -// This example demonstrates the four most common operations: -// -// GET /?action=set&key=foo&value=bar -> Cache.set -// GET /?action=get&key=foo -> Cache.get -// GET /?action=exists&key=foo -> Cache.exists -// GET /?action=delete&key=foo -> Cache.delete - -import { Cache } from 'fastedge::cache'; - -async function eventHandler(event) { - try { - const url = new URL(event.request.url); - const action = url.searchParams.get('action'); - const key = url.searchParams.get('key'); - - if (!key) { - throw new Error('Missing required query parameter: "key"'); - } - - switch (action) { - case 'set': { - // Cache.set writes a value under `key`. Accepts strings, - // ArrayBuffers, ArrayBufferViews, ReadableStreams, and Response - // objects (the body is consumed; status and headers are not stored). - // - // The `{ ttl: 60 }` option means "expire 60 seconds from now". You - // can also use `ttlMs` for sub-second precision, or `expiresAt` for - // a fixed Unix-epoch deadline. Omit options entirely for no expiry. - const value = url.searchParams.get('value') ?? ''; - await Cache.set(key, value, { ttl: 60 }); - return Response.json({ action, key, value, ttl: 60 }); - } - - case 'get': { - // Cache.get returns a CacheEntry on a hit, or `null` on a miss - // (key absent or expired). The cache stores raw bytes, so on read - // you choose how to decode using one of: - // entry.text() -> Promise (UTF-8) - // entry.json() -> Promise (parsed JSON) - // entry.arrayBuffer() -> Promise - const entry = await Cache.get(key); - if (entry === null) { - return Response.json({ action, key, hit: false }); - } - const value = await entry.text(); - return Response.json({ action, key, hit: true, value }); - } - - case 'exists': { - // Cache.exists is a cheap presence check — useful when you only - // need to know whether a key is set without transferring its value - // (e.g. idempotency-key checks, "have we seen this token?"). - const present = await Cache.exists(key); - return Response.json({ action, key, present }); - } - - case 'delete': { - // Cache.delete removes the entry. It is a no-op if the key is - // already absent — no error is thrown. - await Cache.delete(key); - return Response.json({ action, key, deleted: true }); - } - - default: - throw new Error( - `Unknown action: "${action}". Use one of: set, get, exists, delete.`, - ); - } - } catch (error) { - // Validation errors (e.g. wrong types, conflicting WriteOptions fields) - // are thrown synchronously; host errors (access denied, internal error) - // arrive as Promise rejections. Both are caught by this single handler. - return Response.json({ error: error.message }, { status: 500 }); - } -} - -addEventListener('fetch', (event) => { - event.respondWith(eventHandler(event)); -}); -``` - -### FILE: examples/cache-basic/package.json - -```json -{ - "name": "fastedge-example-cache-basic", - "version": "1.0.0", - "description": "FastEdge JS example: simple Cache set/get/exists/delete operations", - "type": "module", - "scripts": { - "build": "fastedge-build src/index.js dist/cache-basic.wasm" - }, - "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.3.0" - } -} -``` diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/cache-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/cache-ts.md index 82141f5..fb89a00 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/cache-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/cache-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -283,7 +283,7 @@ addEventListener('fetch', (event: FetchEvent) => { ```json { "scripts": { "build": "fastedge-build -c" }, - "dependencies": { "@gcoredev/fastedge-sdk-js": "^2.3.0" } + "dependencies": { "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` @@ -315,281 +315,3 @@ Build command: `fastedge-build -c` - http-base skeleton (base event listener and fetch handler structure) - platform-overview (POP-local vs. global state trade-offs) - best-practices (key naming conventions, TTL selection, error handling) - -## Source Material - -### FILE: examples/cache/src/index.ts - -```ts -// FastEdge Cache — flagship patterns -// -// This example demonstrates the three highest-value uses of the -// `fastedge::cache` module: -// -// 1. Per-IP rate limiting (atomic counters) -// 2. Origin-cache proxy (manual get/set with conditional caching) -// 3. JSON memoisation (getOrSet with a computed populator) -// -// All three patterns rely on the cache being: -// - **Strongly consistent within a POP** — atomic `incr` returns a -// correct count under concurrent load, which `fastedge::kv` cannot. -// - **Fast for both reads and writes** — sub-millisecond on the hot -// path, so caching is cheaper than recomputing or refetching. -// - **POP-local** — values do not replicate across data centers. -// This is acceptable (and often desirable) for transient state. - -import { Cache } from 'fastedge::cache'; - -// --------------------------------------------------------------------------- -// Pattern 1 — Rate limiting via atomic incr + expire -// --------------------------------------------------------------------------- -// -// Increment a per-IP counter. On the first hit (count === 1) we attach -// a TTL to create a fixed 60-second window anchored to that request: -// the counter resets 60 seconds after the user's *first* request, not -// after every request. -// -// `Cache.incr` is atomic: under concurrent load, two simultaneous -// requests cannot both see "count === 1" and double-set the expiry. -// This is the property that makes the cache suitable for limiting, -// quotas, locks, and other counter primitives. - -const RATE_LIMIT_MAX = 10; // Requests per window. -const RATE_LIMIT_WINDOW_S = 60; // Window length, seconds. - -async function rateLimit(event: FetchEvent): Promise { - // `event.client.address` is the trusted-edge client IP. Sourced from - // `x-real-ip` (with fallback to `x-forwarded-for`); both are set by - // the FastEdge POP, not the client, so they're safe to key on. - const ip = event.client.address || 'unknown'; - - const key = `rl:${ip}`; - - const count = await Cache.incr(key); - - // Only set the expiry on the first hit of a new window. If we set it - // on every request, the window would never close — each new request - // would push the deadline another 60 seconds out. - if (count === 1) { - await Cache.expire(key, { ttl: RATE_LIMIT_WINDOW_S }); - } - - if (count > RATE_LIMIT_MAX) { - return Response.json( - { error: 'Too Many Requests', limit: RATE_LIMIT_MAX, count }, - { status: 429, headers: { 'retry-after': String(RATE_LIMIT_WINDOW_S) } }, - ); - } - - return Response.json({ - pattern: 'rate-limit', - ip, - count, - remaining: RATE_LIMIT_MAX - count, - windowSeconds: RATE_LIMIT_WINDOW_S, - }); -} - -// --------------------------------------------------------------------------- -// Pattern 2 — Origin-cache proxy with conditional caching -// --------------------------------------------------------------------------- -// -// Cache successful upstream responses for PROXY_TTL_S seconds; pass -// non-2xx and redirects through *without* caching, so a transient 404 -// or 500 doesn't get pinned for the rest of the window. The cache is -// a byte cache (no status/headers), so we only cache when "200 OK with -// application/octet-stream" is a faithful replay of the upstream. -// -// `getOrSet` is not used here because its populator can't signal -// "fetched, but don't cache" — we need that distinction to handle -// error responses safely. See Pattern 3 for `getOrSet` in a context -// where every populator output is cacheable. - -const PROXY_TTL_S = 30; - -async function proxy(url: string): Promise { - // Validate the URL before we use it as a cache key. - let parsed: URL; - try { - parsed = new URL(url); - } catch { - return Response.json({ error: `Invalid url: "${url}"` }, { status: 400 }); - } - - // Strip the fragment: fetch() never sends it to the origin, so - // `https://example.com/#a` and `#b` are the same upstream resource - // and must share one cache entry. - parsed.hash = ''; - - const key = `proxy:${parsed.toString()}`; - - // Cache hit — replay the bytes as 200 OK. Status/headers from the - // original response are not preserved by the byte cache. - const cached = await Cache.get(key); - if (cached !== null) { - return new Response(await cached.arrayBuffer(), { - headers: { - 'content-type': 'application/octet-stream', - 'x-cache': 'hit', - 'x-cache-ttl': String(PROXY_TTL_S), - }, - }); - } - - // Cache miss — fetch upstream and only cache successful responses. - // Non-2xx and redirects flow through unchanged so callers see the - // real status code instead of a synthetic 200. - const upstream = await fetch(parsed.toString()); - if (!upstream.ok) { - return upstream; - } - - const bytes = await upstream.arrayBuffer(); - await Cache.set(key, bytes, { ttl: PROXY_TTL_S }); - return new Response(bytes, { - headers: { - 'content-type': 'application/octet-stream', - 'x-cache': 'miss', - 'x-cache-ttl': String(PROXY_TTL_S), - }, - }); -} - -// --------------------------------------------------------------------------- -// Pattern 3 — JSON memoisation via getOrSet with a computed populator -// --------------------------------------------------------------------------- -// -// Same shape as the proxy pattern, but the populator does CPU work -// instead of network I/O. Use this whenever you compute the same -// expensive answer many times in a row — search index lookups, -// signed-token verification, derived report rollups, JSON -// transformations of slow-changing source data. -// -// We embed `generatedAt` in the result so a client refreshing the -// page can see the timestamp stay constant within the cache window -// and update once it expires. - -const MEMO_TTL_S = 60; - -async function memo(): Promise { - const entry = await Cache.getOrSet( - 'memo:report', - () => { - // Stand-in for "expensive computation". The populator can be - // synchronous or async — both are accepted. - const report = { - generatedAt: new Date().toISOString(), - topItems: ['alpha', 'beta', 'gamma'].map((name, i) => ({ - name, - score: Math.round(Math.random() * 1000) / 10, - rank: i + 1, - })), - }; - // The populator returns the value to store. Because we want - // structured JSON back later, we serialise here and re-parse - // via `entry.json()` on read. - return JSON.stringify(report); - }, - { ttl: MEMO_TTL_S }, - ); - - // `entry.json()` parses the cached UTF-8 bytes as JSON. Use - // `entry.text()` for a string, or `entry.arrayBuffer()` for bytes. - const report = await entry.json(); - - return Response.json({ - pattern: 'memo', - note: `Cached for ${MEMO_TTL_S}s. Refresh to confirm 'generatedAt' stays the same until expiry.`, - report, - }); -} - -// --------------------------------------------------------------------------- -// Default landing — usage menu when no action is supplied -// --------------------------------------------------------------------------- - -function landing(): Response { - return Response.json({ - name: 'FastEdge Cache patterns', - actions: { - 'rate-limit': '/?action=rate-limit', - proxy: '/?action=proxy&url=https://www.example.com', - memo: '/?action=memo', - }, - }); -} - -// --------------------------------------------------------------------------- -// Router -// --------------------------------------------------------------------------- - -async function eventHandler(event: FetchEvent): Promise { - try { - const url = new URL(event.request.url); - const action = url.searchParams.get('action'); - - switch (action) { - case 'rate-limit': - return await rateLimit(event); - case 'proxy': - return await proxy(url.searchParams.get('url') ?? ''); - case 'memo': - return await memo(); - case null: - return landing(); - default: - return Response.json( - { error: `Unknown action: "${action}". Use one of: rate-limit, proxy, memo.` }, - { status: 400 }, - ); - } - } catch (error: unknown) { - // Validation errors thrown by Cache.* (e.g. conflicting WriteOptions - // fields) are synchronous; host errors arrive as Promise rejections. - // Both are caught by this single handler. - return Response.json({ error: (error as Error).message }, { status: 500 }); - } -} - -addEventListener('fetch', (event: FetchEvent) => { - event.respondWith(eventHandler(event)); -}); -``` - - -### FILE: examples/cache/package.json - -```json -{ - "name": "fastedge-example-cache", - "version": "1.0.0", - "description": "FastEdge JS example: Cache patterns — rate limiting, origin-cache proxy, memoisation", - "type": "module", - "scripts": { - "build": "fastedge-build -c" - }, - "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.3.0" - } -} -``` - - -### FILE: examples/cache/tsconfig.json - -```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"] -} -``` diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/crypto-hmac-jwt-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/crypto-hmac-jwt-ts.md index 643e5bd..061921b 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/crypto-hmac-jwt-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/crypto-hmac-jwt-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -28,7 +28,7 @@ Use this blueprint when the app must authenticate requests by verifying HS256-si ```json { - "@gcoredev/fastedge-sdk-js": "^2.2.2" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } ``` @@ -353,7 +353,7 @@ addEventListener('fetch', (event) => { "build": "fastedge-build src/index.js dist/crypto-hmac-jwt.wasm" }, "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.2.2" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/fetch-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/fetch-ts.md index c24356c..15caf30 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/fetch-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/fetch-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- type: feature @@ -82,7 +82,7 @@ addEventListener('fetch', (event) => { - The response from the downstream service is returned directly to the client (status, headers, and body are all proxied through). - This is the simplest possible pattern for outbound HTTP. For more complex scenarios, inspect `event.request` to build dynamic downstream URLs, add headers, or transform the response before returning it. - The downstream URL can be hardcoded or read from environment variables using `getEnv` (see the headers or geo-redirect examples for that pattern). -- SDK version is `^2.2.2` in `package.json`. +- SDK version is `^2.5.2` in `package.json`. ## Source Material @@ -139,7 +139,7 @@ addEventListener('fetch', (event) => { "build": "fastedge-build src/index.js dist/outbound-fetch.wasm" }, "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.2.2" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/geo-redirect-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/geo-redirect-ts.md index 1fba134..8d758a8 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/geo-redirect-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/geo-redirect-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- type: feature @@ -113,7 +113,7 @@ addEventListener('fetch', (event) => { - Environment variables are set in the Gcore dashboard or via the API when creating or updating the FastEdge app. - Country-specific origins are configured as environment variables using ISO 3166-1 alpha-2 codes. If no matching variable exists, `BASE_ORIGIN` is used as the fallback. - If `BASE_ORIGIN` is not set, the handler returns HTTP 500 with a descriptive error message. -- SDK dependency: `@gcoredev/fastedge-sdk-js` `^2.3.0` (as of source commit `9c8c7886f0d1ec5ac2296b4080805966a96ca817`). +- SDK dependency: `@gcoredev/fastedge-sdk-js` `^2.5.2` (as of source commit `9c8c7886f0d1ec5ac2296b4080805966a96ca817`). ## Source Material @@ -157,7 +157,7 @@ addEventListener('fetch', (event) => { "build": "fastedge-build src/index.js dist/geo-redirect.wasm" }, "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.3.0" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/headers-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/headers-ts.md index dad0d40..223276e 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/headers-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/headers-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -121,7 +121,7 @@ getEnv(name: string): string | null - Build command: `fastedge-build src/index.js dist/headers.wasm` - Defined in `package.json` scripts as `"build": "fastedge-build src/index.js dist/headers.wasm"`. -- `@gcoredev/fastedge-sdk-js` version constraint: `^2.3.0`. +- `@gcoredev/fastedge-sdk-js` version constraint: `^2.5.2`. - Package type must be `"module"` (ESM) in `package.json`. ## Source Material Reference @@ -166,7 +166,7 @@ addEventListener('fetch', (event) => { "build": "fastedge-build src/index.js dist/headers.wasm" }, "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.3.0" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/kv-store-basic-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/kv-store-basic-ts.md index 108a855..7565245 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/kv-store-basic-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/kv-store-basic-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -111,7 +111,7 @@ Build script from `package.json`: - Entry point: `src/index.js` - Output: `dist/kv-store-basic.wasm` -- SDK dependency: `@gcoredev/fastedge-sdk-js` `^2.3.0` +- SDK dependency: `@gcoredev/fastedge-sdk-js` `^2.5.2` - Module type: `"type": "module"` (ESM) ## Constraints @@ -167,7 +167,7 @@ addEventListener('fetch', (event) => { "build": "fastedge-build src/index.js dist/kv-store-basic.wasm" }, "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.3.0" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/kv-store-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/kv-store-ts.md index 4b23e8a..5aaa1b8 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/kv-store-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/kv-store-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -29,7 +29,7 @@ No additional npm dependencies beyond the base skeleton. The KV Store API is pro ```json { "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.3.0" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` @@ -286,3 +286,189 @@ Missing required parameters return HTTP 500 with JSON `{ "error": "..." }`. - The KV store must be pre-created in the Gcore dashboard or API before the app can use it. The store name is passed at runtime (e.g., as a query parameter). - Available KV operations: `get`, `scan`, `zrangeByScore`, `zscan`, `bfExists`. - `tsconfig.json` uses `"moduleResolution": "Bundler"` and `"target": "ES2023"`. Do not use `"moduleResolution": "Node"` or older ES targets with this SDK version. + +## Source Material + +### FILE: examples/kv-store/src/index.ts + +```ts +import { KvStore } from 'fastedge::kv'; + +import { Action, decodeValueArray, stringifyValueScoreTuples, validateQueryParams } from './utils'; + +async function eventHandler(event: FetchEvent): Promise { + try { + const { request: req } = event; + const url = new URL(req.url); + + const params = validateQueryParams(url.searchParams); + if (params.error) { + throw new Error(params.error); + } + + const myStore = KvStore.open(params.store); + const action = params.action as Action; + + const responseObj: Record = { + Store: params.store, + Action: action, + }; + + switch (action) { + case 'get': { + const response = myStore.get(params.key); + responseObj.Key = params.key; + responseObj.Response = decodeValueArray(response); + break; + } + case 'scan': { + const response = myStore.scan(params.match); + responseObj.Match = params.match; + responseObj.Response = response.join(', '); + break; + } + case 'zrange': { + const { key, min, max } = params; + const response = myStore.zrangeByScore(key, Number.parseFloat(min), Number.parseFloat(max)); + responseObj.Key = key; + responseObj.Min = min; + responseObj.Max = max; + responseObj.Response = stringifyValueScoreTuples(response); + break; + } + case 'zscan': { + const { key, match } = params; + const response = myStore.zscan(key, match); + responseObj.Key = key; + responseObj.Match = match; + responseObj.Response = stringifyValueScoreTuples(response); + break; + } + case 'bfExists': { + const { key, item } = params; + const exists = myStore.bfExists(key, item); + responseObj.Key = key; + responseObj.Item = item; + responseObj.Response = exists ? 'true' : 'false'; + break; + } + default: + break; + } + + return Response.json(responseObj); + } catch (error: Error | unknown) { + return Response.json({ error: `${(error as Error).message}` }, { status: 500 }); + } +} + +addEventListener('fetch', (event: FetchEvent) => { + event.respondWith(eventHandler(event)); +}); +``` + + +### FILE: examples/kv-store/src/utils.ts + +```ts +const ALL_ACTIONS = ['get', 'scan', 'zscan', 'zrange', 'bfExists'] as const; + +export type Action = (typeof ALL_ACTIONS)[number]; + +type ParamKey = 'action' | 'store' | 'key' | 'match' | 'min' | 'max' | 'item' | 'error'; + +type Params = { [key in ParamKey]: string }; + +export function validateQueryParams(queryParams: URLSearchParams): Params { + const validParams = {} as Params; + + // Validate 'action' parameter + const action = queryParams.get('action') ?? 'get'; + if (ALL_ACTIONS.includes(action as Action)) { + validParams.action = action; + } else { + validParams.error = `Invalid action '${action}'. Supported actions are: ${ALL_ACTIONS.join( + ', ', + )}`; + return validParams; + } + + const requiredParameters = { + store: [...ALL_ACTIONS], + key: ['get', 'zrange', 'zscan', 'bfExists'], + match: ['scan', 'zscan'], + min: ['zrange'], + max: ['zrange'], + item: ['bfExists'], + } as Record>; + + for (const [key, actions] of Object.entries(requiredParameters)) { + if (actions.includes(action)) { + const value = queryParams.get(key); + if (value && value !== '') { + validParams[key as ParamKey] = value; + } else { + validParams.error = `Query parameters must provide '${key}' for a '${action}' action.`; + return validParams; + } + } + } + + return validParams; +} + +export const decodeValueArray = (arrVal: ArrayBuffer | null) => { + if (arrVal) { + const decoder = new TextDecoder(); + return decoder.decode(arrVal); + } + return ''; +}; + +export const stringifyValueScoreTuples = (tupleList: Array<[ArrayBuffer, number]>): string => { + let strResponse = '['; + for (const tuple of tupleList) { + strResponse += `{ Value: ${decodeValueArray(tuple[0])}, Score: ${tuple[1]} }, `; + } + strResponse += ']'; + return strResponse; +}; +``` + + +### FILE: examples/kv-store/package.json + +```json +{ + "name": "fastedge-example-kv-store", + "version": "1.0.0", + "description": "FastEdge JS example: KV Store operations via query params", + "type": "module", + "scripts": { + "build": "fastedge-build -c" + }, + "dependencies": { + "@gcoredev/fastedge-sdk-js": "^2.5.2" + } +} +``` + + +### FILE: examples/kv-store/tsconfig.json + +```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"] +} +``` diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/mcp-server-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/mcp-server-ts.md index 055d200..7b82d60 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/mcp-server-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/mcp-server-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -211,7 +211,7 @@ export default server; ### `src/types.ts` -Include verbatim — these response type definitions are required by the tool handlers in `server.ts`. Generate this file with the correct interface shapes matching the NWS API (or replace with types for the target API): +Include verbatim — these response type definitions are required by the tool handlers in `server.ts`: ```typescript export interface AlertProperties { @@ -288,7 +288,7 @@ Include verbatim: ### Runtime dependencies ```json -"@gcoredev/fastedge-sdk-js": "^2.3.0", +"@gcoredev/fastedge-sdk-js": "^2.5.2", "@hono/mcp": "^0.2.5", "@modelcontextprotocol/sdk": "^1.29.0", "hono": "^4.13.5", diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/outbound-modify-response-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/outbound-modify-response-ts.md index 45cb96b..538c561 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/outbound-modify-response-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/outbound-modify-response-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -122,12 +122,14 @@ From `package.json`: ```json { "name": "fastedge-example-outbound-modify-response", + "version": "1.0.0", + "description": "FastEdge JS example: fetch and modify outbound response", "type": "module", "scripts": { "build": "fastedge-build src/index.js dist/outbound-modify-response.wasm" }, "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.2.2" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` @@ -145,3 +147,49 @@ From `package.json`: - sdk-reference-js (fetch API, Response constructor, addEventListener) - deploy skill reference (uploading and registering the compiled WASM binary) - outbound-fetch feature blueprint (fetch without body transformation) + +## Source Material + +### FILE: examples/outbound-modify-response/src/index.js + +```js +async function app(event) { + const outboundResponse = await fetch('http://jsonplaceholder.typicode.com/users'); + const users = await outboundResponse.json(); + return new Response( + JSON.stringify({ + users: users.slice(0, 5), + total: 5, + skip: 0, + limit: 30, + }), + { + status: 200, + headers: { + 'content-type': 'application/json', + }, + }, + ); +} + +addEventListener('fetch', (event) => { + event.respondWith(app(event)); +}); +``` + +### FILE: examples/outbound-modify-response/package.json + +```json +{ + "name": "fastedge-example-outbound-modify-response", + "version": "1.0.0", + "description": "FastEdge JS example: fetch and modify outbound response", + "type": "module", + "scripts": { + "build": "fastedge-build src/index.js dist/outbound-modify-response.wasm" + }, + "dependencies": { + "@gcoredev/fastedge-sdk-js": "^2.5.2" + } +} +``` diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/react-with-hono-server-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/react-with-hono-server-ts.md index 50dc4c2..79a9b30 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/react-with-hono-server-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/react-with-hono-server-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -34,7 +34,7 @@ Over `http-base`, add the following to `package.json`. **Runtime dependencies:** ```json -"@gcoredev/fastedge-sdk-js": "^2.3.0", +"@gcoredev/fastedge-sdk-js": "^2.5.2", "hono": "^4.13.5", "react": "^19.1.1", "react-dom": "^19.1.1" @@ -124,7 +124,7 @@ Script semantics: "preview": "vite preview" }, "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.3.0", + "@gcoredev/fastedge-sdk-js": "^2.5.2", "hono": "^4.13.5", "react": "^19.1.1", "react-dom": "^19.1.1" diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/request-inspection-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/request-inspection-ts.md index 2f1f255..4373c3a 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/request-inspection-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/request-inspection-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -120,7 +120,7 @@ Setting `content-type: text/plain; charset=utf-8` makes the response human-reada "build": "fastedge-build src/index.js dist/request-inspection.wasm" }, "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.2.2" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` @@ -182,7 +182,7 @@ addEventListener('fetch', (event) => { "build": "fastedge-build src/index.js dist/request-inspection.wasm" }, "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.2.2" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/secret-rotation-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/secret-rotation-ts.md index 4da7354..caf0581 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/secret-rotation-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/secret-rotation-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -186,7 +186,7 @@ This shape is the diagnostic surface for verifying that rotation is working corr ```json { "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.2.2" + "@gcoredev/fastedge-sdk-js": "^2.5.2" } } ``` diff --git a/plugins/gcore-fastedge/skills/scaffold/reference/http/static-assets-ts.md b/plugins/gcore-fastedge/skills/scaffold/reference/http/static-assets-ts.md index dbd2a9b..d40d06b 100644 --- a/plugins/gcore-fastedge/skills/scaffold/reference/http/static-assets-ts.md +++ b/plugins/gcore-fastedge/skills/scaffold/reference/http/static-assets-ts.md @@ -2,9 +2,9 @@ auto-updated: true sources: - id: fastedge-sdk-js - ref: main + ref: v2.5.2 commit: 9c8c7886f0d1ec5ac2296b4080805966a96ca817 - updated: 2026-09-22 + updated: 2026-10-02 --> --- @@ -311,7 +311,7 @@ footer a { "author": "", "license": "ISC", "dependencies": { - "@gcoredev/fastedge-sdk-js": "^2.3.0", + "@gcoredev/fastedge-sdk-js": "^2.5.2", "hono": "^4.13.5" }, "devDependencies": { @@ -347,7 +347,7 @@ Additions over `http-base`: | Package | Type | Version | |---|---|---| -| `@gcoredev/fastedge-sdk-js` | runtime | `^2.3.0` | +| `@gcoredev/fastedge-sdk-js` | runtime | `^2.5.2` | | `hono` | runtime | `^4.13.5` | | `npm-run-all2` | devDependency | `^9.0.2` | @@ -483,3 +483,334 @@ The build entry point is `src/index.tsx` (not `.ts`). `tsconfig.json` must inclu - static-sites guide (end-to-end walkthrough of building and deploying a static site on FastEdge) - http-base blueprint (base skeleton this feature extends) - sdk-reference-js (full `@gcoredev/fastedge-sdk-js` API surface) + +## Source Material + +### FILE: examples/static-assets/src/index.tsx + +```ts +import { createStaticServer } from '@gcoredev/fastedge-sdk-js'; +import { Hono } from 'hono'; + +import { staticAssetManifest as imagesStaticAssets } from './images-static-assets'; +import { JsxContent } from './jsx-page'; +import { staticAssetManifest as stylesStaticAssets } from './styles-static-assets'; +import { staticAssetManifest as templatesStaticAssets } from './templates-static-assets'; + +const imagesStaticServer = createStaticServer(imagesStaticAssets, { + routePrefix: 'images', +}); + +const stylesStaticServer = createStaticServer(stylesStaticAssets, { + routePrefix: 'styles', +}); + +const templatesStaticServer = createStaticServer(templatesStaticAssets, {}); + +const app = new Hono(); + +app.get('/', async (c) => c.html( + + + Test Site + + + +

Home Page

+

Basic HTML rendering

+ + + + , + )); + +app.get('/jsx', async (c) => { + const props = { + name: 'World', + siteData: { + title: 'Hello <> World', + description: 'This is a description', + }, + }; + return c.html(); +}); + +app.get('/styles/*', async (c) => stylesStaticServer.serveRequest(c.req.raw)); + +app.get('/images/*', async (c) => imagesStaticServer.serveRequest(c.req.raw)); + +app.get('/template', async (c) => { + const templateString = await templatesStaticServer.readFileString('/index.html'); + return c.html(templateString); +}); + +addEventListener('fetch', (event: FetchEvent) => { + event.respondWith(app.fetch(event.request)); +}); + +``` + + +### FILE: examples/static-assets/src/jsx-page.tsx + +```ts +import { html } from 'hono/html'; + +interface SiteData { + title: string; + description: string; + children?: unknown; +} + +const Layout = (props: SiteData) => html` + + + + ${props.title} + + + + + + + + ${props.children} + + +`; + +const Footer = () => ( + +); + +const JsxContent = (props: { siteData: SiteData; name: string }) => ( + +

JSX rendered Page

+

Hello {props.name}

+

This is the JSX rendered page. Example of how to use Hono html rendering.

+ + Hono HTML Helper Documentation + +
+ + Home Button + +
+