@fepro/workhub-app-sdk 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +318 -0
- package/README.md +22 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/index.ts +31 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# AGENTS.md — building WorkHub apps with AI assistance
|
|
2
|
+
|
|
3
|
+
> Read this once, generate working apps in one shot. This file is optimised
|
|
4
|
+
> for AI coding agents (Claude, GPT, Aider, Cursor, etc.). Humans prefer the
|
|
5
|
+
> [README.md](./README.md). Both describe the same SDK; this one is denser,
|
|
6
|
+
> includes complete worked examples, and lists the gotchas that bite agents.
|
|
7
|
+
|
|
8
|
+
## What you are building
|
|
9
|
+
|
|
10
|
+
A **WorkHub app** is a `.zip` archive containing a static SPA + a manifest.
|
|
11
|
+
The host (WorkHub portal) renders it as a sandboxed iframe inside the
|
|
12
|
+
tenant's `/apps/<slug>` route. Apps cannot call the WorkHub API directly —
|
|
13
|
+
every cross-origin call goes through `@fepro/workhub-app-sdk`, which sends
|
|
14
|
+
typed `postMessage` RPCs to the host bridge. The bridge enforces the
|
|
15
|
+
manifest's declared scopes and forwards approved calls to `/v1/*`.
|
|
16
|
+
|
|
17
|
+
## One-shot mental model
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
zip post bridge api
|
|
21
|
+
───── ──── ────── ───
|
|
22
|
+
index.html ◄── iframe ── │ ◄── postMessage ── workhub.identity.current()
|
|
23
|
+
workhub.json │ │ ▼
|
|
24
|
+
assets/... │ └─── HTTP ───► /v1/apps/bridge/context
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The agent's job: produce `index.html` (or `dist/`) + `workhub.json`, zip them, upload.
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
The platform serves the SDK from the portal origin at **`/sdk.js`** — uploaded
|
|
32
|
+
apps can load it directly without any build step or external CDN. This is the
|
|
33
|
+
recommended path for hand-written and AI-generated bundles:
|
|
34
|
+
|
|
35
|
+
```html
|
|
36
|
+
<script type="module">
|
|
37
|
+
import { workhub } from '/sdk.js';
|
|
38
|
+
</script>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For TypeScript projects with a build step:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install @fepro/workhub-app-sdk
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { workhub } from '@fepro/workhub-app-sdk';
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
> Do **not** use cross-origin CDNs (esm.sh, jsdelivr, unpkg, etc.). Uploaded
|
|
52
|
+
> apps run inside a sandboxed iframe whose CSP is `default-src 'self'`, so
|
|
53
|
+
> external script loads are blocked. `/sdk.js` is same-origin and works.
|
|
54
|
+
|
|
55
|
+
## Manifest spec — `workhub.json` (zip root)
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"key": "lower-kebab-id",
|
|
60
|
+
"name": "Display Name",
|
|
61
|
+
"version": "1.0.0",
|
|
62
|
+
"description": "One-line summary",
|
|
63
|
+
"entry": "index.html",
|
|
64
|
+
"icon": "assets/icon.svg",
|
|
65
|
+
"scopes": [
|
|
66
|
+
"identity:read",
|
|
67
|
+
"storage:read",
|
|
68
|
+
"storage:write",
|
|
69
|
+
"notifications:send",
|
|
70
|
+
"events:listen",
|
|
71
|
+
"api:proxy"
|
|
72
|
+
]
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Rules:
|
|
77
|
+
- `key` must match `^[a-z0-9][a-z0-9-]*[a-z0-9]$` (2–80 chars). Stable identifier — re-uploads with the same key upgrade in place.
|
|
78
|
+
- `entry` defaults to `index.html`. Path is relative to the zip root.
|
|
79
|
+
- `scopes` is exact match — only declare what you actually call. Bridge rejects calls whose required scope is missing with `ERR_SCOPE_DENIED`.
|
|
80
|
+
|
|
81
|
+
## SDK surface — every method, every type
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
// Identity ---------------------------------------------------
|
|
85
|
+
workhub.identity.current(): Promise<{
|
|
86
|
+
user: { id: string; displayName: string | null; email: string | null } | null;
|
|
87
|
+
tenant: { id: string; name: string } | null;
|
|
88
|
+
installation: { id: string; slug: string; displayName: string };
|
|
89
|
+
manifest: unknown; // your workhub.json snapshot
|
|
90
|
+
scopes: string[];
|
|
91
|
+
}>;
|
|
92
|
+
|
|
93
|
+
// Storage — KV scoped to (tenant, installation) -------------
|
|
94
|
+
workhub.storage.get<T = unknown>(key: string): Promise<T | null>;
|
|
95
|
+
workhub.storage.set<T>(key: string, value: T, opts?: { ttlSeconds?: number }): Promise<void>;
|
|
96
|
+
workhub.storage.delete(key: string): Promise<void>;
|
|
97
|
+
workhub.storage.list(prefix?: string): Promise<Array<{ key: string; value: unknown; updatedAt: string }>>;
|
|
98
|
+
|
|
99
|
+
// Notifications ---------------------------------------------
|
|
100
|
+
workhub.notifications.toast(
|
|
101
|
+
message: string,
|
|
102
|
+
opts?: { variant?: 'info' | 'success' | 'warning' | 'danger' },
|
|
103
|
+
): Promise<void>;
|
|
104
|
+
|
|
105
|
+
// Events — host pushes these as the user navigates / themes -
|
|
106
|
+
type Names = 'theme:change' | 'route:change' | 'tenant:switch';
|
|
107
|
+
workhub.events.on(name: Names, cb: (payload: unknown) => void): () => void; // returns unsubscribe
|
|
108
|
+
|
|
109
|
+
// Generic API escape hatch ----------------------------------
|
|
110
|
+
workhub.api.call<T>(verb: string, body?: unknown): Promise<T>;
|
|
111
|
+
// verb format: "METHOD /v1/path" e.g. "GET /v1/databases"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Scope → method matrix
|
|
115
|
+
|
|
116
|
+
| scope | unlocks |
|
|
117
|
+
| -------------------- | ---------------------------------------- |
|
|
118
|
+
| `identity:read` | `identity.current()` |
|
|
119
|
+
| `storage:read` | `storage.get`, `storage.list` |
|
|
120
|
+
| `storage:write` | `storage.set`, `storage.delete` |
|
|
121
|
+
| `notifications:send` | `notifications.toast` |
|
|
122
|
+
| `events:listen` | `events.on(...)` |
|
|
123
|
+
| `api:proxy` | `api.call(verb, body)` (still gated on the user's existing /v1 permissions) |
|
|
124
|
+
|
|
125
|
+
## Worked examples
|
|
126
|
+
|
|
127
|
+
### Example 1 — Minimal hello app (vanilla, zero deps)
|
|
128
|
+
|
|
129
|
+
`workhub.json`:
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"key": "hello",
|
|
133
|
+
"name": "Hello App",
|
|
134
|
+
"version": "1.0.0",
|
|
135
|
+
"scopes": ["identity:read", "notifications:send"]
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`index.html`:
|
|
140
|
+
```html
|
|
141
|
+
<!doctype html>
|
|
142
|
+
<html><body>
|
|
143
|
+
<h1 id="greeting">Loading…</h1>
|
|
144
|
+
<button id="ping">Toast</button>
|
|
145
|
+
<script type="module">
|
|
146
|
+
import { workhub } from '/sdk.js';
|
|
147
|
+
const me = await workhub.identity.current();
|
|
148
|
+
greeting.textContent = `Hi ${me.user?.displayName ?? 'there'} (${me.tenant?.name})`;
|
|
149
|
+
ping.onclick = () => workhub.notifications.toast('Hello from your app!', { variant: 'success' });
|
|
150
|
+
</script>
|
|
151
|
+
</body></html>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Example 2 — Persistent settings (TS + Vite)
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
import { workhub } from '@fepro/workhub-app-sdk';
|
|
158
|
+
|
|
159
|
+
interface Settings { darkMode: boolean; pageSize: number }
|
|
160
|
+
|
|
161
|
+
async function loadSettings(): Promise<Settings> {
|
|
162
|
+
const stored = await workhub.storage.get<Settings>('settings');
|
|
163
|
+
return stored ?? { darkMode: false, pageSize: 25 };
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function saveSettings(s: Settings): Promise<void> {
|
|
167
|
+
await workhub.storage.set('settings', s);
|
|
168
|
+
await workhub.notifications.toast('Settings saved', { variant: 'success' });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// React to host theme changes so the app follows the portal's light/dark.
|
|
172
|
+
workhub.events.on('theme:change', (p: any) => {
|
|
173
|
+
document.documentElement.dataset.theme = p.mode;
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Manifest scopes: `["identity:read","storage:read","storage:write","notifications:send","events:listen"]`
|
|
178
|
+
|
|
179
|
+
### Example 3 — App that lists the tenant's databases
|
|
180
|
+
|
|
181
|
+
```ts
|
|
182
|
+
import { workhub } from '@fepro/workhub-app-sdk';
|
|
183
|
+
|
|
184
|
+
interface DatabaseInstance { id: string; name: string; engine: string; status: string }
|
|
185
|
+
|
|
186
|
+
async function listDatabases(): Promise<DatabaseInstance[]> {
|
|
187
|
+
const res = await workhub.api.call<{ items: DatabaseInstance[] }>('GET /v1/databases');
|
|
188
|
+
return res.items;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const dbs = await listDatabases();
|
|
192
|
+
document.body.innerHTML = `<ul>${dbs.map((d) => `<li>${d.name} (${d.engine}) — ${d.status}</li>`).join('')}</ul>`;
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Manifest scopes: `["api:proxy"]` — note the user must also hold `database.read` for the call to succeed; the bridge does not elevate.
|
|
196
|
+
|
|
197
|
+
## Build + upload commands
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
# 1. Build your SPA into ./dist (or the directory containing index.html + assets)
|
|
201
|
+
npm run build
|
|
202
|
+
|
|
203
|
+
# 2. Copy the manifest in next to the built files
|
|
204
|
+
cp workhub.json dist/
|
|
205
|
+
|
|
206
|
+
# 3. Zip from INSIDE dist/ — the manifest must be at zip root, not nested.
|
|
207
|
+
cd dist && zip -r ../my-app.zip . && cd ..
|
|
208
|
+
|
|
209
|
+
# 4. Upload via the portal
|
|
210
|
+
open https://your-portal/apps/development
|
|
211
|
+
|
|
212
|
+
# Or via the API
|
|
213
|
+
curl -X POST https://your-portal-api/v1/apps/dev/upload \
|
|
214
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
215
|
+
-F bundle=@my-app.zip
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Security model — what the iframe can and cannot do
|
|
219
|
+
|
|
220
|
+
WorkHub apps run in a **fully sandboxed iframe** with `sandbox="allow-scripts allow-forms"`. That means:
|
|
221
|
+
|
|
222
|
+
- **No DOM access to the parent portal** — the iframe gets an opaque origin and cannot reach into `parent.document` or strip its own sandbox.
|
|
223
|
+
- **No cross-origin `fetch`** — `connect-src 'self'` in the iframe's CSP blocks calls to anything other than the runtime host. Use `workhub.api.call(...)` to reach `/v1/*` instead.
|
|
224
|
+
- **No external script CDNs** — `default-src 'self'` blocks loading scripts/styles from esm.sh, jsdelivr, unpkg, etc. Either bundle dependencies or import them via the platform-served `/sdk.js`.
|
|
225
|
+
- **`localStorage` / `IndexedDB` work** — but they're partitioned per-frame because of the opaque origin. State persists across reloads of the same installation; cross-app sharing isn't possible (use the SDK's `storage.*` for shared, server-backed KV).
|
|
226
|
+
- **No cookies inside the iframe** — for the same reason. Anything that needs auth goes through the SDK's `api.call(...)`, where the host parent attaches the user's session.
|
|
227
|
+
|
|
228
|
+
This is a **production security boundary**. A malicious bundle uploaded by tenant A cannot read tenant B's portal data, manipulate the parent UI, or call /v1 endpoints on the user's behalf without going through the scope-enforcing SDK bridge.
|
|
229
|
+
|
|
230
|
+
## Gotchas (the things that bite agents)
|
|
231
|
+
|
|
232
|
+
1. **Manifest at zip root, not nested in a folder.** `unzip -l` should show `workhub.json` directly, not `dist/workhub.json` or `my-app/workhub.json`. The upload endpoint reads the manifest from the root entry.
|
|
233
|
+
2. **Don't ship `node_modules` or build configs.** Bundle the compiled output only — the upload limit is 25 MB compressed.
|
|
234
|
+
3. **`postMessage` requires the iframe to be embedded.** Calling SDK methods locally in a browser tab outside the portal returns `not_embedded`. There's no offline mock in v1 — develop by uploading and iterating, or stub the SDK methods locally with mocks.
|
|
235
|
+
4. **Scope enforcement is exact.** Calling `storage.set` without `storage:write` rejects with `{ code: 'ERR_SCOPE_DENIED' }` — the call never leaves the iframe.
|
|
236
|
+
5. **`api.call('GET /v1/...')`** verb format is `"METHOD path"` with a single space. Lowercase methods are accepted but normalised.
|
|
237
|
+
6. **Storage values are JSON-serialisable.** Functions, `BigInt`, `Date` (use ISO strings), and circular references all fail. Storage payload max is whatever Postgres `jsonb` accepts (~1 GB practical, but keep entries small).
|
|
238
|
+
7. **`storage.list(prefix)`** uses `LIKE 'prefix%'` matching — pick a prefix scheme that doesn't collide.
|
|
239
|
+
8. **Events fire from the host, not from your code.** `workhub.events.on('theme:change', ...)` returns an unsubscribe function — wire it into your component cleanup if you have one.
|
|
240
|
+
9. **CSP locks `connect-src` to `'self'`** by default, meaning `fetch()` to third-party origins from inside the iframe is blocked. Use `workhub.api.call(...)` to reach `/v1/*`. For external HTTP, the host would need a `proxy:fetch` scope (not in v1).
|
|
241
|
+
10. **Bundle URLs are short-cached (60s).** Iterate by re-uploading; the bundle key includes a content hash so a fresh upload gets a fresh URL automatically.
|
|
242
|
+
11. **Always import the SDK from `/sdk.js`** — never `https://esm.sh/...`, `https://cdn.jsdelivr.net/...`, or any other CDN. The iframe's CSP blocks them. `/sdk.js` is the platform's same-origin SDK and works under sandbox.
|
|
243
|
+
|
|
244
|
+
## Error catalogue
|
|
245
|
+
|
|
246
|
+
| code | meaning | fix |
|
|
247
|
+
| ------------------ | ----------------------------------------------------- | ----------------------------------------- |
|
|
248
|
+
| `not_embedded` | SDK called outside an iframe | run inside the portal |
|
|
249
|
+
| `ERR_SCOPE_DENIED` | manifest doesn't declare the required scope | add the scope to `workhub.json` + re-upload |
|
|
250
|
+
| `rpc_timeout` | host bridge didn't respond in 10s | check network / portal logs |
|
|
251
|
+
| `unknown_verb` | SDK method not implemented in the bridge | likely an SDK/host version mismatch |
|
|
252
|
+
| `bridge_400/4xx` | API rejected the underlying call | inspect `error.message` for details |
|
|
253
|
+
| `http_403` | `api.call` succeeded but the user lacks `/v1` perms | tenant grants more permissions to the user |
|
|
254
|
+
|
|
255
|
+
## Starter template (copy verbatim)
|
|
256
|
+
|
|
257
|
+
```
|
|
258
|
+
my-app/
|
|
259
|
+
├── workhub.json
|
|
260
|
+
├── index.html
|
|
261
|
+
└── assets/
|
|
262
|
+
└── icon.svg
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
`workhub.json`:
|
|
266
|
+
```json
|
|
267
|
+
{
|
|
268
|
+
"key": "my-app",
|
|
269
|
+
"name": "My App",
|
|
270
|
+
"version": "0.1.0",
|
|
271
|
+
"entry": "index.html",
|
|
272
|
+
"icon": "assets/icon.svg",
|
|
273
|
+
"scopes": ["identity:read", "storage:read", "storage:write", "notifications:send", "events:listen"]
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
`index.html`:
|
|
278
|
+
```html
|
|
279
|
+
<!doctype html>
|
|
280
|
+
<html lang="en">
|
|
281
|
+
<head>
|
|
282
|
+
<meta charset="utf-8" />
|
|
283
|
+
<title>My App</title>
|
|
284
|
+
<style>
|
|
285
|
+
:root { color-scheme: light dark; font-family: system-ui, sans-serif; }
|
|
286
|
+
body { margin: 0; padding: 24px; max-width: 720px; }
|
|
287
|
+
[data-theme="dark"] body { background: #0e1116; color: #e6e6e6; }
|
|
288
|
+
button { padding: 8px 14px; border-radius: 6px; cursor: pointer; }
|
|
289
|
+
</style>
|
|
290
|
+
</head>
|
|
291
|
+
<body>
|
|
292
|
+
<h1 id="title">Loading…</h1>
|
|
293
|
+
<p><input id="note" placeholder="type something" /> <button id="save">Save</button></p>
|
|
294
|
+
<pre id="out"></pre>
|
|
295
|
+
<script type="module">
|
|
296
|
+
import { workhub } from '/sdk.js';
|
|
297
|
+
const me = await workhub.identity.current();
|
|
298
|
+
title.textContent = `Hi ${me.user?.displayName ?? 'tenant'}`;
|
|
299
|
+
const last = await workhub.storage.get('note');
|
|
300
|
+
if (last) note.value = last;
|
|
301
|
+
save.onclick = async () => {
|
|
302
|
+
await workhub.storage.set('note', note.value);
|
|
303
|
+
out.textContent = JSON.stringify(await workhub.storage.list(), null, 2);
|
|
304
|
+
await workhub.notifications.toast('Saved', { variant: 'success' });
|
|
305
|
+
};
|
|
306
|
+
workhub.events.on('theme:change', (p) => document.documentElement.dataset.theme = p.mode);
|
|
307
|
+
</script>
|
|
308
|
+
</body>
|
|
309
|
+
</html>
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Zip + upload:
|
|
313
|
+
```bash
|
|
314
|
+
zip -r my-app.zip workhub.json index.html assets/
|
|
315
|
+
# then upload via /apps/development → Upload bundle
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
That's a complete, working WorkHub app. Modify and ship.
|
package/README.md
CHANGED
|
@@ -2,8 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
Client SDK for apps embedded inside the WorkHub portal.
|
|
4
4
|
|
|
5
|
+
> **Building with an AI agent?** See [AGENTS.md](./AGENTS.md) (or fetch
|
|
6
|
+
> [https://workhub.dev/sdk/agents.md](https://workhub.dev/sdk/agents.md))
|
|
7
|
+
> for a dense, machine-friendly reference with the full SDK surface, three
|
|
8
|
+
> worked examples, the gotcha catalogue, and a copy-paste starter template.
|
|
9
|
+
|
|
5
10
|
## Install
|
|
6
11
|
|
|
12
|
+
The platform serves the compiled SDK at **`/sdk.js`** on the portal origin —
|
|
13
|
+
uploaded apps can import it without any build step or external CDN. This is
|
|
14
|
+
the recommended path for hand-written and AI-generated bundles:
|
|
15
|
+
|
|
16
|
+
```html
|
|
17
|
+
<script type="module">
|
|
18
|
+
import { workhub } from '/sdk.js';
|
|
19
|
+
</script>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
For TypeScript projects with a build step:
|
|
23
|
+
|
|
7
24
|
```bash
|
|
8
25
|
npm install @fepro/workhub-app-sdk
|
|
9
26
|
# or
|
|
@@ -12,6 +29,11 @@ pnpm add @fepro/workhub-app-sdk
|
|
|
12
29
|
yarn add @fepro/workhub-app-sdk
|
|
13
30
|
```
|
|
14
31
|
|
|
32
|
+
> **Do not use cross-origin CDNs** (esm.sh, jsdelivr, unpkg, etc.). Uploaded
|
|
33
|
+
> apps run inside a fully sandboxed iframe whose CSP is `default-src 'self'`,
|
|
34
|
+
> which blocks external script loads. `/sdk.js` is the same-origin platform
|
|
35
|
+
> SDK and is the only supported way to load it without bundling.
|
|
36
|
+
|
|
15
37
|
## The bundle format
|
|
16
38
|
|
|
17
39
|
A WorkHub developer-app is a `.zip` archive with this layout:
|
package/dist/index.d.ts
CHANGED
|
@@ -93,6 +93,22 @@ export declare const workhub: {
|
|
|
93
93
|
readonly api: {
|
|
94
94
|
readonly call: <T = unknown>(verb: string, body?: unknown) => Promise<T>;
|
|
95
95
|
};
|
|
96
|
+
/** Calls the developer's own workspace backend, proxied through the
|
|
97
|
+
* WorkHub runtime so requests carry a verifiable identity token (the
|
|
98
|
+
* backend SDK verifies it against /.well-known/jwks.json).
|
|
99
|
+
*
|
|
100
|
+
* Only available to apps installed under a developer workspace — for
|
|
101
|
+
* standalone-iframe apps this method throws because the runtime has
|
|
102
|
+
* no backend deployment to forward to. */
|
|
103
|
+
readonly backend: {
|
|
104
|
+
/** Issue a request against the workspace backend.
|
|
105
|
+
*
|
|
106
|
+
* `path` is the route path declared in the backend's defineWorkspace
|
|
107
|
+
* routes table (e.g. `/leads` or `/leads/123/notes`). Leading slash
|
|
108
|
+
* required. The host SDK builds the full URL `/v1/apps/runtime/<installationId>/api<path>`
|
|
109
|
+
* and uses same-origin credentialed fetch — no extra auth wiring. */
|
|
110
|
+
readonly fetch: (path: string, init?: RequestInit) => Promise<Response>;
|
|
111
|
+
};
|
|
96
112
|
};
|
|
97
113
|
export default workhub;
|
|
98
114
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAI;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAChF,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5C,YAAY,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAChE,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC;AAEnC,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAQ,MAAM,CAAC;IAClB,KAAK,EAAM,YAAY,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,cAAc,GACd,eAAe,CAAC;AAEpB,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAG;QAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAAA;KAAE,CAAC;IAC5C,cAAc,EAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAClC,eAAe,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC;AAsGD,eAAO,MAAM,OAAO;IAClB,iEAAiE;;gCAEpD,OAAO,CAAC,QAAQ,CAAC;;IAK9B;sEACkE;;uBAE5D,CAAC,iBAAsB,MAAM,KAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;uBAGjD,CAAC,iBAAsB,MAAM,SAAS,CAAC,SAAS;YAAE,UAAU,CAAC,EAAE,MAAM,CAAA;SAAE,KAAG,OAAO,CAAC,IAAI,CAAC;+BAG/E,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;iCAGpB,MAAM,KAAG,OAAO,CAAC,YAAY,EAAE,CAAC;;IAKhD;4DACwD;;kCAEvC,MAAM,SAAS;YAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAA;SAAE,KAAG,OAAO,CAAC,IAAI,CAAC;;IAKvG;uDACmD;;;aApDhD,CAAC,SAAS,gBAAgB,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI;mBACzF,MAAM,MAAM,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI;;;IAwD5D;;sDAEkD;;wBAE3C,CAAC,kBAAkB,MAAM,SAAS,OAAO,KAAG,OAAO,CAAC,CAAC,CAAC;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAI;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;IAChF,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC5C,YAAY,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAChE,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC;AAEnC,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAQ,MAAM,CAAC;IAClB,KAAK,EAAM,YAAY,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,cAAc,GACd,eAAe,CAAC;AAEpB,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAG;QAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAAA;KAAE,CAAC;IAC5C,cAAc,EAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAClC,eAAe,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CACvC;AAsGD,eAAO,MAAM,OAAO;IAClB,iEAAiE;;gCAEpD,OAAO,CAAC,QAAQ,CAAC;;IAK9B;sEACkE;;uBAE5D,CAAC,iBAAsB,MAAM,KAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;uBAGjD,CAAC,iBAAsB,MAAM,SAAS,CAAC,SAAS;YAAE,UAAU,CAAC,EAAE,MAAM,CAAA;SAAE,KAAG,OAAO,CAAC,IAAI,CAAC;+BAG/E,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;iCAGpB,MAAM,KAAG,OAAO,CAAC,YAAY,EAAE,CAAC;;IAKhD;4DACwD;;kCAEvC,MAAM,SAAS;YAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAA;SAAE,KAAG,OAAO,CAAC,IAAI,CAAC;;IAKvG;uDACmD;;;aApDhD,CAAC,SAAS,gBAAgB,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI;mBACzF,MAAM,MAAM,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI;;;IAwD5D;;sDAEkD;;wBAE3C,CAAC,kBAAkB,MAAM,SAAS,OAAO,KAAG,OAAO,CAAC,CAAC,CAAC;;IAK7D;;;;;;+CAM2C;;QAEzC;;;;;8EAKsE;+BACpD,MAAM,SAAS,WAAW,KAAG,OAAO,CAAC,QAAQ,CAAC;;CAgB1D,CAAC;AAGX,eAAe,OAAO,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -141,6 +141,36 @@ export const workhub = {
|
|
|
141
141
|
return channel.call('api.call', { verb, body });
|
|
142
142
|
},
|
|
143
143
|
},
|
|
144
|
+
/** Calls the developer's own workspace backend, proxied through the
|
|
145
|
+
* WorkHub runtime so requests carry a verifiable identity token (the
|
|
146
|
+
* backend SDK verifies it against /.well-known/jwks.json).
|
|
147
|
+
*
|
|
148
|
+
* Only available to apps installed under a developer workspace — for
|
|
149
|
+
* standalone-iframe apps this method throws because the runtime has
|
|
150
|
+
* no backend deployment to forward to. */
|
|
151
|
+
backend: {
|
|
152
|
+
/** Issue a request against the workspace backend.
|
|
153
|
+
*
|
|
154
|
+
* `path` is the route path declared in the backend's defineWorkspace
|
|
155
|
+
* routes table (e.g. `/leads` or `/leads/123/notes`). Leading slash
|
|
156
|
+
* required. The host SDK builds the full URL `/v1/apps/runtime/<installationId>/api<path>`
|
|
157
|
+
* and uses same-origin credentialed fetch — no extra auth wiring. */
|
|
158
|
+
async fetch(path, init) {
|
|
159
|
+
if (!path.startsWith('/')) {
|
|
160
|
+
throw new Error(`workhub.backend.fetch: path must start with "/" — got "${path}"`);
|
|
161
|
+
}
|
|
162
|
+
const identity = await channel.call('identity.current', {});
|
|
163
|
+
const installationId = identity.installation?.id;
|
|
164
|
+
if (!installationId) {
|
|
165
|
+
throw new Error('workhub.backend.fetch: no installation id on identity — is this app installed under a workspace?');
|
|
166
|
+
}
|
|
167
|
+
const url = `/v1/apps/runtime/${encodeURIComponent(installationId)}/api${path}`;
|
|
168
|
+
return fetch(url, {
|
|
169
|
+
...init,
|
|
170
|
+
credentials: 'include',
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
},
|
|
144
174
|
};
|
|
145
175
|
// Default export for ergonomic single-import usage.
|
|
146
176
|
export default workhub;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAwDH,MAAM,cAAc,GAAG,MAAM,CAAC;AAE9B,MAAM,WAAW;IACP,MAAM,GAAG,CAAC,CAAC;IACX,OAAO,GAAG,IAAI,GAAG,EAAyE,CAAC;IACnG,yDAAyD;IACjD,SAAS,GAAG,IAAI,GAAG,EAA2C,CAAC;IACvE,qEAAqE;IAC7D,KAAK,GAAG,KAAK,CAAC;IAEd,IAAI;QACV,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO;QACvB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO;QAC1C,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,KAAmB,EAAE,EAAE;YACzD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAmC,CAAC;YACvD,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAK,IAA+B,CAAC,SAAS,KAAK,SAAS;gBAAE,OAAO;YAC1G,sEAAsE;YACtE,qEAAqE;YACrE,sEAAsE;YACtE,uBAAuB;YACvB,IAAI,IAAI,CAAC,SAAS,KAAK,cAAc,EAAE,CAAC;gBACtC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC1C,IAAI,CAAC,OAAO;oBAAE,OAAO;gBACrB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC7B,IAAI,IAAI,CAAC,EAAE;oBAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;;oBACrC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,IAAI,YAAY,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC;YAC9H,CAAC;iBAAM,IAAI,IAAI,CAAC,SAAS,KAAK,WAAW,EAAE,CAAC;gBAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC1C,IAAI,CAAC,GAAG;oBAAE,OAAO;gBACjB,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;oBACrB,IAAI,CAAC;wBAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBAAC,CAAC;oBAAC,MAAM,CAAC,CAAC,6BAA6B,CAAC,CAAC;gBACnE,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAI,IAAY,EAAE,OAAgB;QACpC,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC9D,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAC,CAAC;QACpG,CAAC;QACD,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACjC,MAAM,GAAG,GAAe,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QACxE,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACpC,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACxC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC9B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACxB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,gBAAgB,IAAI,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;YAChF,CAAC,EAAE,cAAc,CAAC,CAAC;YACnB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE;gBACnB,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAM,CAAC,CAAC,CAAC,CAAC;gBAC3D,MAAM,EAAG,CAAC,CAAC,EAAE,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;aACtD,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAID,EAAE,CAAC,IAAY,EAAE,EAA8B;QAC7C,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,IAAI,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC;YAChB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAChC,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACZ,OAAO,GAAG,EAAE,CAAC,GAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;AAElC,+EAA+E;AAE/E,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,iEAAiE;IACjE,QAAQ,EAAE;QACR,OAAO;YACL,OAAO,OAAO,CAAC,IAAI,CAAW,kBAAkB,EAAE,EAAE,CAAC,CAAC;QACxD,CAAC;KACF;IAED;sEACkE;IAClE,OAAO,EAAE;QACP,GAAG,CAAmB,GAAW;YAC/B,OAAO,OAAO,CAAC,IAAI,CAAW,aAAa,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QACxD,CAAC;QACD,GAAG,CAAmB,GAAW,EAAE,KAAQ,EAAE,IAA8B;YACzE,OAAO,OAAO,CAAC,IAAI,CAAO,aAAa,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QACzF,CAAC;QACD,MAAM,CAAC,GAAW;YAChB,OAAO,OAAO,CAAC,IAAI,CAAO,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,CAAC,MAAe;YAClB,OAAO,OAAO,CAAC,IAAI,CAAiB,cAAc,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;QAClE,CAAC;KACF;IAED;4DACwD;IACxD,aAAa,EAAE;QACb,KAAK,CAAC,OAAe,EAAE,IAA8D;YACnF,OAAO,OAAO,CAAC,IAAI,CAAO,qBAAqB,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,MAAM,EAAE,CAAC,CAAC;QAClG,CAAC;KACF;IAED;uDACmD;IACnD,MAAM,EAAE;QACN,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC;KAC7B;IAED;;sDAEkD;IAClD,GAAG,EAAE;QACH,IAAI,CAAc,IAAY,EAAE,IAAc;YAC5C,OAAO,OAAO,CAAC,IAAI,CAAI,UAAU,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,CAAC;KACF;CACO,CAAC;AAEX,oDAAoD;AACpD,eAAe,OAAO,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fepro/workhub-app-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Client SDK for apps embedded in WorkHub. Use it inside an iframe app to call back into the host (identity, storage, notifications, events, API proxy).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
19
19
|
"src",
|
|
20
|
-
"README.md"
|
|
20
|
+
"README.md",
|
|
21
|
+
"AGENTS.md"
|
|
21
22
|
],
|
|
22
23
|
"scripts": {
|
|
23
24
|
"build": "tsc -p tsconfig.json",
|
package/src/index.ts
CHANGED
|
@@ -198,6 +198,37 @@ export const workhub = {
|
|
|
198
198
|
return channel.call<T>('api.call', { verb, body });
|
|
199
199
|
},
|
|
200
200
|
},
|
|
201
|
+
|
|
202
|
+
/** Calls the developer's own workspace backend, proxied through the
|
|
203
|
+
* WorkHub runtime so requests carry a verifiable identity token (the
|
|
204
|
+
* backend SDK verifies it against /.well-known/jwks.json).
|
|
205
|
+
*
|
|
206
|
+
* Only available to apps installed under a developer workspace — for
|
|
207
|
+
* standalone-iframe apps this method throws because the runtime has
|
|
208
|
+
* no backend deployment to forward to. */
|
|
209
|
+
backend: {
|
|
210
|
+
/** Issue a request against the workspace backend.
|
|
211
|
+
*
|
|
212
|
+
* `path` is the route path declared in the backend's defineWorkspace
|
|
213
|
+
* routes table (e.g. `/leads` or `/leads/123/notes`). Leading slash
|
|
214
|
+
* required. The host SDK builds the full URL `/v1/apps/runtime/<installationId>/api<path>`
|
|
215
|
+
* and uses same-origin credentialed fetch — no extra auth wiring. */
|
|
216
|
+
async fetch(path: string, init?: RequestInit): Promise<Response> {
|
|
217
|
+
if (!path.startsWith('/')) {
|
|
218
|
+
throw new Error(`workhub.backend.fetch: path must start with "/" — got "${path}"`);
|
|
219
|
+
}
|
|
220
|
+
const identity = await channel.call<Identity>('identity.current', {});
|
|
221
|
+
const installationId = identity.installation?.id;
|
|
222
|
+
if (!installationId) {
|
|
223
|
+
throw new Error('workhub.backend.fetch: no installation id on identity — is this app installed under a workspace?');
|
|
224
|
+
}
|
|
225
|
+
const url = `/v1/apps/runtime/${encodeURIComponent(installationId)}/api${path}`;
|
|
226
|
+
return fetch(url, {
|
|
227
|
+
...init,
|
|
228
|
+
credentials: 'include',
|
|
229
|
+
});
|
|
230
|
+
},
|
|
231
|
+
},
|
|
201
232
|
} as const;
|
|
202
233
|
|
|
203
234
|
// Default export for ergonomic single-import usage.
|