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
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.
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 bundlenpm run clean– remove build artifacts
Project structure
src/– TypeScript sources implementing thehandlerexport defined inwit/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/jsfor the intermediate JS bundle,dist/main.wasmfor the component artifact).
Building
Using the Alga CLI (recommended):
npm install
npm run build # runs: alga build
Or directly with the CLI:
alga build
The final component artifact will be written to dist/main.wasm.
Packaging
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:
- Create a wrapper
index.tsthat imports WIT functions and buildsHostBindings - Use a custom build script with external imports
Example: Accessing User Info
Create src/index.ts:
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:
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:
{
"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, Scheduler Host API Guide, and Invoicing Host API Guide for detailed usage.
Next steps
- Implement your business logic inside
src/handler.ts(orsrc/handler-impl.tsif 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 buildandnpm run packto create a distributable bundle. - Use
alga extension publishto upload your extension to an Alga instance.