u
This commit is contained in:
126
src/defaultSkills/applet.SKILL
Normal file
126
src/defaultSkills/applet.SKILL
Normal file
@@ -0,0 +1,126 @@
|
||||
Applet Guide: Sandboxed Execution, Typed CSV Output
|
||||
|
||||
# Overview
|
||||
An applet is a flat, reusable `.applet.js` script stored in the VFS that queries Dashback REST endpoints and computes tabular data.
|
||||
Applets return structured, semicolon-separated (`;`) typed CSV conforming to output metadata headers.
|
||||
|
||||
Applets can be executed by:
|
||||
1. `javascript_execute` tool using `{ "appletvfsfile": "<name>.applet.js", "applet_input": { ... } }`.
|
||||
2. REST API endpoint `POST /vfs/<name>.applet.js` with `{ "input": { ... } }`.
|
||||
|
||||
---
|
||||
|
||||
# Every `.applet.js` file MUST start with three metadata lines:
|
||||
|
||||
```
|
||||
// @applet-input-schema {"type":"object","properties":{...},"required":[...]}
|
||||
// @applet-output-schema name:type;name:type
|
||||
// @applet-description "Lorem ipsum"
|
||||
```
|
||||
|
||||
`@applet-input-schema`
|
||||
- JSON Schema object (`"type": "object"`).
|
||||
- Parameter descriptions in the schema are optional
|
||||
|
||||
`@applet-output-schema`
|
||||
- Semicolon-separated (`col1:type;col2:type;...`) column declarations.
|
||||
- Bare column names without `:type` default to `string`.
|
||||
- Allowed data types:
|
||||
- `string`: plain text or serialized object.
|
||||
- `integer`: truncated integer number.
|
||||
- `number`: floating-point number.
|
||||
- `boolean`: boolean value (`true`, `false`, `1`, `0`, `"true"`, `"false"`).
|
||||
- `date`: Date object or ISO string.
|
||||
|
||||
---
|
||||
|
||||
# Execution Environment & Globals
|
||||
|
||||
Applets run in an isolated worker thread pool sandbox.
|
||||
|
||||
- **Entry point**: Export an async function taking `applet_input`:
|
||||
```javascript
|
||||
module.exports = async function (applet_input) { ... };
|
||||
```
|
||||
- **No `require()` or `import`**: Attempting to import modules throws an error.
|
||||
- **Pre-injected Globals**:
|
||||
- `fetch(path, options)`: Authenticated `fetch` pre-configured with a JWT scoped to the current user and selected company. Use root-relative API routes, e.g. `fetch('/article/42000009')`.
|
||||
- `fs` / `vfs`: Sandboxed VFS filesystem interface for reading/writing local company files.
|
||||
- `ExcelJS`: Pre-injected spreadsheet library.
|
||||
- `PDFDocument`: Pre-injected PDFKit library.
|
||||
- `sharp`: Pre-injected image manipulation library.
|
||||
- `crypto`: Node / WebCrypto API.
|
||||
- `console.log(...)`: returned in the tool response
|
||||
|
||||
---
|
||||
|
||||
# Return Value & Typed CSV Mapping
|
||||
|
||||
The exported function must return:
|
||||
- An **Array of row objects**: `[ { col1: 'val1', col2: 10 }, { col1: 'val2', col2: 20 } ]`
|
||||
- Or a **Single row object**: `{ col1: 'val1', col2: 10 }` (treated as a 1-row table)
|
||||
|
||||
---
|
||||
|
||||
# Standard Applet Template
|
||||
|
||||
```javascript
|
||||
// @applet-input-schema {"type":"object","properties":{"sku":{"type":"string","title":"Article SKU","description":"SKU to lookup"}},"required":["sku"]}
|
||||
// @applet-output-schema sku:string;name:string;netPrice:number;tracked:boolean;brand:string
|
||||
// @applet-description "Lorem ipsum"
|
||||
|
||||
module.exports = async function (applet_input) {
|
||||
const sku = String(applet_input?.sku || '').trim();
|
||||
if (!sku) {
|
||||
throw new Error('Missing required parameter: sku');
|
||||
}
|
||||
|
||||
const res = await fetch(`/article/${encodeURIComponent(sku)}`);
|
||||
if (res.status === 404) throw new Error(`Article "${sku}" not found.`);
|
||||
if (!res.ok) throw new Error(`GET /article/${sku} failed with status ${res.status}`);
|
||||
|
||||
const { article } = await res.json();
|
||||
const price = (article.prices || [])[0];
|
||||
|
||||
console.log(`Found article ${article.sku}: ${article.name}`);
|
||||
|
||||
return [{
|
||||
sku: article.sku,
|
||||
name: article.name || '',
|
||||
netPrice: price?.net ?? '',
|
||||
tracked: Boolean(article.track_stock),
|
||||
brand: article.brand?.name || ''
|
||||
}];
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Common Implementation Patterns
|
||||
|
||||
### 1. Paging List Endpoints
|
||||
Page using `offset` and `limit` until all items are loaded or `limit` is reached:
|
||||
```javascript
|
||||
const items = [];
|
||||
let offset = 0;
|
||||
while (true) {
|
||||
const res = await fetch(`/order?offset=${offset}&limit=100`);
|
||||
if (!res.ok) throw new Error(`Fetch failed: ${res.status}`);
|
||||
const data = await res.json();
|
||||
const page = data.orders || [];
|
||||
items.push(...page);
|
||||
offset += page.length;
|
||||
if (page.length === 0 || offset >= (data.total ?? items.length)) break;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Shipped Reference Applets
|
||||
|
||||
Pre-installed examples in the VFS root provide working reference code:
|
||||
- `v1-article-lookup.applet.js`: Single entity lookup and key/value sheet generation.
|
||||
- `v1-article-catalogue.applet.js`: Walking category trees and joining category article lists.
|
||||
- `v1-category-inventory.applet.js`: Recursive tree flattening and depth calculation.
|
||||
- `v1-delivery-register.applet.js`: Paged list fetching with batched detail requests.
|
||||
- `v1-order-revenue-by-month.applet.js`: Paged order retrieval with calendar month aggregation.
|
||||
Reference in New Issue
Block a user