Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
138 lines
5.0 KiB
Markdown
138 lines
5.0 KiB
Markdown
# __PACKAGE_NAME__ Component Template
|
||
|
||
This project was generated with `alga create component`. It targets the Alga extension runner
|
||
using the WebAssembly Component Model and [`componentize-js`](https://github.com/bytecodealliance/componentize-js).
|
||
|
||
## Available scripts
|
||
|
||
- `npm run build` – build the extension using the Alga CLI (compiles TypeScript and produces WASM)
|
||
- `npm run pack` – package the extension into a distributable bundle
|
||
- `npm run clean` – remove build artifacts
|
||
|
||
## Project structure
|
||
|
||
- `src/` – TypeScript sources implementing the `handler` export defined in `wit/extension-runner.wit`.
|
||
- `src/types.ts` – convenience copies of the WIT data structures for use in TypeScript.
|
||
- `wit/extension-runner.wit` – WIT world definitions describing the host capabilities exposed by the runner.
|
||
- `dist/` – build output (`dist/js` for the intermediate JS bundle, `dist/main.wasm` for the component artifact).
|
||
|
||
## Building
|
||
|
||
**Using the Alga CLI (recommended):**
|
||
|
||
```bash
|
||
npm install
|
||
npm run build # runs: alga build
|
||
```
|
||
|
||
Or directly with the CLI:
|
||
|
||
```bash
|
||
alga build
|
||
```
|
||
|
||
The final component artifact will be written to `dist/main.wasm`.
|
||
|
||
## Packaging
|
||
|
||
```bash
|
||
npm run pack # runs: alga pack
|
||
```
|
||
|
||
This creates a `bundle.tar.zst` archive containing the manifest, WASM component, and any UI assets.
|
||
|
||
## Using Host Capabilities
|
||
|
||
To use host capabilities like logging, user info, secrets, or storage, you need to:
|
||
|
||
1. **Create a wrapper `index.ts`** that imports WIT functions and builds `HostBindings`
|
||
2. **Use a custom build script** with external imports
|
||
|
||
### Example: Accessing User Info
|
||
|
||
Create `src/index.ts`:
|
||
|
||
```typescript
|
||
import { handler as userHandler } from './handler-impl.js';
|
||
import { ExecuteRequest, ExecuteResponse, HostBindings, normalizeUserData } from '@alga-psa/extension-runtime';
|
||
|
||
// @ts-ignore - WIT imports resolved at runtime
|
||
import { getUser } from 'alga:extension/user-v2';
|
||
// @ts-ignore
|
||
import { logInfo, logWarn, logError } from 'alga:extension/logging';
|
||
// @ts-ignore
|
||
import { getContext } from 'alga:extension/context';
|
||
|
||
const host: HostBindings = {
|
||
context: { get: async () => getContext() },
|
||
logging: {
|
||
info: async (msg) => logInfo(msg),
|
||
warn: async (msg) => logWarn(msg),
|
||
error: async (msg) => logError(msg),
|
||
},
|
||
user: { getUser: async () => normalizeUserData(await getUser()) },
|
||
// Add other bindings as needed
|
||
};
|
||
|
||
export async function handler(request: ExecuteRequest): Promise<ExecuteResponse> {
|
||
return userHandler(request, host);
|
||
}
|
||
```
|
||
|
||
Rename your handler to `src/handler-impl.ts` and update the signature:
|
||
|
||
```typescript
|
||
import { ExecuteRequest, ExecuteResponse, HostBindings, jsonResponse } from '@alga-psa/extension-runtime';
|
||
|
||
export async function handler(request: ExecuteRequest, host: HostBindings): Promise<ExecuteResponse> {
|
||
// Now you can use host bindings
|
||
const user = await host.user.getUser();
|
||
await host.logging.info(`Request from ${user.userName}`);
|
||
|
||
return jsonResponse({
|
||
ok: true,
|
||
user: { name: user.userName, type: user.userType },
|
||
});
|
||
}
|
||
```
|
||
|
||
Update `package.json` with a custom build:
|
||
|
||
```json
|
||
{
|
||
"scripts": {
|
||
"build:backend": "esbuild src/index.ts --bundle --format=esm --platform=neutral --outfile=dist/js/index.js --external:alga:extension/secrets --external:alga:extension/http --external:alga:extension/storage --external:alga:extension/logging --external:alga:extension/ui-proxy --external:alga:extension/context --external:alga:extension/user --external:alga:extension/user-v2",
|
||
"build:component": "jco componentize dist/js/index.js --wit ./wit/extension-runner.wit --world-name runner --disable all --out dist/main.wasm",
|
||
"build": "npm run build:backend && npm run build:component"
|
||
},
|
||
"devDependencies": {
|
||
"@bytecodealliance/jco": "^1.8.0",
|
||
"esbuild": "^0.20.0"
|
||
}
|
||
}
|
||
```
|
||
|
||
## Available Host Capabilities
|
||
|
||
| Capability | Interface | Description |
|
||
|------------|-----------|-------------|
|
||
| `cap:context.read` | `context` | Execution context (tenant, extension IDs) |
|
||
| `cap:secrets.get` | `secrets` | Install-scoped secrets |
|
||
| `cap:http.fetch` | `http` | Outbound HTTP requests |
|
||
| `cap:storage.kv` | `storage` | Key-value storage |
|
||
| `cap:log.emit` | `logging` | Structured logging |
|
||
| `cap:ui.proxy` | `ui-proxy` | UI proxy routes |
|
||
| `cap:user.read` | `user` | Current user info (default) |
|
||
| `cap:scheduler.manage` | `scheduler` | Scheduled tasks |
|
||
| `cap:invoice.manual.create` | `invoicing` | Create draft manual invoices |
|
||
|
||
See the [User Host API Guide](../../../docs/guides/user-host-api.md), [Scheduler Host API Guide](../../../docs/guides/scheduler-host-api.md), and [Invoicing Host API Guide](../../../docs/guides/invoicing-host-api.md) for detailed usage.
|
||
|
||
## Next steps
|
||
|
||
- Implement your business logic inside `src/handler.ts` (or `src/handler-impl.ts` if using host bindings).
|
||
- Use the host capabilities to interact with secrets, storage, user info, etc.
|
||
- Add tests (e.g., using Vitest) that exercise your handler logic.
|
||
- When ready, run `npm run build` and `npm run pack` to create a distributable bundle.
|
||
- Use `alga extension publish` to upload your extension to an Alga instance.
|