frontier-os-app-builder 1.1.0 → 1.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/LICENSE +21 -0
- package/README.md +25 -0
- package/agents/fos-executor.md +22 -65
- package/agents/fos-plan-checker.md +13 -12
- package/agents/fos-planner.md +20 -67
- package/agents/fos-researcher.md +14 -10
- package/agents/fos-verifier.md +11 -5
- package/bin/fos-tools.cjs +48 -11
- package/bin/install.js +8 -5
- package/commands/fos/add-feature.md +1 -2
- package/commands/fos/discuss.md +0 -1
- package/commands/fos/new-app.md +1 -3
- package/commands/fos/new-milestone.md +1 -1
- package/commands/fos/plan.md +0 -2
- package/package.json +7 -1
- package/references/app-patterns.md +46 -28
- package/references/deployment.md +40 -74
- package/references/module-index.md +32 -0
- package/references/sdk/chain.md +92 -0
- package/references/sdk/communities.md +159 -0
- package/references/sdk/events.md +212 -0
- package/references/sdk/init.md +126 -0
- package/references/sdk/navigation.md +49 -0
- package/references/sdk/offices.md +76 -0
- package/references/sdk/partnerships.md +111 -0
- package/references/sdk/storage.md +44 -0
- package/references/sdk/thirdparty.md +240 -0
- package/references/sdk/token-amount.md +99 -0
- package/references/sdk/types.md +27 -0
- package/references/sdk/ui-utils.md +39 -0
- package/references/sdk/user.md +208 -0
- package/references/sdk/wallet.md +334 -0
- package/references/verification-rules.md +18 -18
- package/templates/app/frontier-services.tsx +75 -18
- package/templates/app/layout.tsx +19 -9
- package/templates/app/package.json +2 -1
- package/templates/app/public/favicon.svg +3 -0
- package/templates/app/sdk-context.tsx +7 -9
- package/templates/app/sdk-services.tsx +92 -117
- package/templates/app/vercel.json +8 -47
- package/templates/state/plan.md +32 -14
- package/templates/state/roadmap.md +2 -2
- package/templates/state/summary.md +26 -29
- package/workflows/add-feature.md +6 -1
- package/workflows/discuss.md +9 -3
- package/workflows/execute-plan.md +3 -3
- package/workflows/execute.md +17 -6
- package/workflows/new-app.md +54 -18
- package/workflows/new-milestone.md +9 -2
- package/workflows/plan.md +14 -5
- package/workflows/ship.md +26 -10
- package/workflows/status.md +0 -1
- package/references/module-inference.md +0 -348
- package/references/sdk-surface.md +0 -1600
- package/templates/app/main-simple-standalone.tsx +0 -19
- package/templates/app/main-simple.tsx +0 -19
- package/templates/state/manifest.json +0 -12
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# ThirdParty Module
|
|
2
|
+
|
|
3
|
+
**Trigger keywords:** developer, api key, webhook, app registration, app store, third party, integration, external, developer portal
|
|
4
|
+
|
|
5
|
+
Access via `sdk.getThirdParty()`. Manage developer accounts, registered apps, and webhooks.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Developer Methods
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
listDevelopers(payload?: ListParams): Promise<PaginatedResponse<Developer>>
|
|
13
|
+
```
|
|
14
|
+
List developer accounts, paginated. Permission: `thirdParty:listDevelopers`
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
getDeveloper(payload: { id: number }): Promise<Developer>
|
|
18
|
+
```
|
|
19
|
+
Get developer details by ID. Permission: `thirdParty:getDeveloper`
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
updateDeveloper(payload: { id: number; data: UpdateDeveloperRequest }): Promise<Developer>
|
|
23
|
+
```
|
|
24
|
+
Update developer information. Permission: `thirdParty:updateDeveloper`
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
rotateDeveloperApiKey(payload: { id: number }): Promise<RotateKeyResponse>
|
|
28
|
+
```
|
|
29
|
+
Rotate developer API key. New key is only shown once in the response. Permission: `thirdParty:rotateDeveloperApiKey`
|
|
30
|
+
|
|
31
|
+
## App Methods
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
listApps(payload?: ListAppsParams): Promise<PaginatedResponse<App>>
|
|
35
|
+
```
|
|
36
|
+
List registered apps, paginated. Optional `developerId` filter. Permission: `thirdParty:listApps`
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
createApp(payload: CreateAppRequest): Promise<App>
|
|
40
|
+
```
|
|
41
|
+
Register a new app. Name, description, and icon are auto-fetched from URL metadata. Permission: `thirdParty:createApp`
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
getApp(payload: { id: number }): Promise<App>
|
|
45
|
+
```
|
|
46
|
+
Get app details by ID. Permission: `thirdParty:getApp`
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
updateApp(payload: { id: number; data: UpdateAppRequest }): Promise<App>
|
|
50
|
+
```
|
|
51
|
+
Update an app. Permission: `thirdParty:updateApp`
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
deleteApp(payload: { id: number }): Promise<void>
|
|
55
|
+
```
|
|
56
|
+
Request app deactivation. Permission: `thirdParty:deleteApp`
|
|
57
|
+
|
|
58
|
+
## Webhook Methods
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
listWebhooks(payload?: ListWebhooksParams): Promise<PaginatedResponse<Webhook>>
|
|
62
|
+
```
|
|
63
|
+
List webhooks, paginated. Max 3 webhooks per developer. Optional `developerId` filter. Permission: `thirdParty:listWebhooks`
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
createWebhook(payload: CreateWebhookRequest): Promise<Webhook>
|
|
67
|
+
```
|
|
68
|
+
Create a new webhook. Requires admin approval before going live. Permission: `thirdParty:createWebhook`
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
getWebhook(payload: { id: number }): Promise<Webhook>
|
|
72
|
+
```
|
|
73
|
+
Get webhook details by ID. Permission: `thirdParty:getWebhook`
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
updateWebhook(payload: { id: number; data: UpdateWebhookRequest }): Promise<Webhook>
|
|
77
|
+
```
|
|
78
|
+
Update a webhook. Config changes require admin re-approval. Permission: `thirdParty:updateWebhook`
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
deleteWebhook(payload: { id: number }): Promise<void>
|
|
82
|
+
```
|
|
83
|
+
Delete a webhook. Permission: `thirdParty:deleteWebhook`
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
rotateWebhookSigningKey(payload: { id: number }): Promise<RotateWebhookKeyResponse>
|
|
87
|
+
```
|
|
88
|
+
Rotate webhook signing key. New public key returned in response. Permission: `thirdParty:rotateWebhookSigningKey`
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Types
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
interface Developer {
|
|
96
|
+
id: number;
|
|
97
|
+
name: string;
|
|
98
|
+
description: string;
|
|
99
|
+
email: string;
|
|
100
|
+
apiKey: string;
|
|
101
|
+
createdAt: string;
|
|
102
|
+
updatedAt: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
interface UpdateDeveloperRequest {
|
|
106
|
+
name?: string;
|
|
107
|
+
description?: string;
|
|
108
|
+
email?: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
interface RotateKeyResponse {
|
|
112
|
+
message: string;
|
|
113
|
+
developer: Developer;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
type AppStatus =
|
|
117
|
+
| 'in_review'
|
|
118
|
+
| 'accepted'
|
|
119
|
+
| 'released'
|
|
120
|
+
| 'rejected'
|
|
121
|
+
| 'request_deactivation'
|
|
122
|
+
| 'deactivated';
|
|
123
|
+
|
|
124
|
+
type AppPermission = string;
|
|
125
|
+
|
|
126
|
+
interface App {
|
|
127
|
+
id: number;
|
|
128
|
+
developer: number;
|
|
129
|
+
icon: string | null;
|
|
130
|
+
name: string;
|
|
131
|
+
readableId: string;
|
|
132
|
+
description: string;
|
|
133
|
+
url: string;
|
|
134
|
+
cnameEntry: string;
|
|
135
|
+
txtEntry: string | null;
|
|
136
|
+
permissions: AppPermission[];
|
|
137
|
+
permissionDisclaimer: string;
|
|
138
|
+
status: AppStatus;
|
|
139
|
+
reviewNotes: string;
|
|
140
|
+
createdAt: string;
|
|
141
|
+
updatedAt: string;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
interface CreateAppRequest {
|
|
145
|
+
developer: number;
|
|
146
|
+
url: string;
|
|
147
|
+
cnameEntry: string;
|
|
148
|
+
txtEntry?: string;
|
|
149
|
+
permissions: AppPermission[];
|
|
150
|
+
permissionDisclaimer: string;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
interface UpdateAppRequest {
|
|
154
|
+
developer?: number;
|
|
155
|
+
url?: string;
|
|
156
|
+
cnameEntry?: string;
|
|
157
|
+
txtEntry?: string;
|
|
158
|
+
permissions?: AppPermission[];
|
|
159
|
+
permissionDisclaimer?: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
type WebhookStatus = 'IN_REVIEW' | 'LIVE' | 'REJECTED';
|
|
163
|
+
type WebhookEvent = string;
|
|
164
|
+
type WebhookScope = Record<string, number[] | '*'>;
|
|
165
|
+
|
|
166
|
+
interface WebhookConfig {
|
|
167
|
+
events: WebhookEvent[];
|
|
168
|
+
scope: WebhookScope;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
interface Webhook {
|
|
172
|
+
id: number;
|
|
173
|
+
developer: number;
|
|
174
|
+
name: string;
|
|
175
|
+
description: string;
|
|
176
|
+
targetUrl: string;
|
|
177
|
+
config: WebhookConfig;
|
|
178
|
+
signingPublicKey: string;
|
|
179
|
+
status: WebhookStatus;
|
|
180
|
+
reviewNotes: string;
|
|
181
|
+
createdAt: string;
|
|
182
|
+
updatedAt: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
interface CreateWebhookRequest {
|
|
186
|
+
developer: number;
|
|
187
|
+
name: string;
|
|
188
|
+
description: string;
|
|
189
|
+
targetUrl: string;
|
|
190
|
+
config: WebhookConfig;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
interface UpdateWebhookRequest {
|
|
194
|
+
developer?: number;
|
|
195
|
+
name?: string;
|
|
196
|
+
description?: string;
|
|
197
|
+
targetUrl?: string;
|
|
198
|
+
config?: WebhookConfig;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
interface RotateWebhookKeyResponse {
|
|
202
|
+
message: string;
|
|
203
|
+
webhook: Webhook;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
interface ListParams {
|
|
207
|
+
limit?: number;
|
|
208
|
+
offset?: number;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
interface ListAppsParams extends ListParams {
|
|
212
|
+
developerId?: number;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
interface ListWebhooksParams extends ListParams {
|
|
216
|
+
developerId?: number;
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Permissions (15)
|
|
223
|
+
|
|
224
|
+
| Permission | Description |
|
|
225
|
+
|---|---|
|
|
226
|
+
| `thirdParty:listDevelopers` | List developer accounts (paginated) |
|
|
227
|
+
| `thirdParty:getDeveloper` | Get developer details by ID |
|
|
228
|
+
| `thirdParty:updateDeveloper` | Update developer information |
|
|
229
|
+
| `thirdParty:rotateDeveloperApiKey` | Rotate developer API key |
|
|
230
|
+
| `thirdParty:listApps` | List registered apps (paginated) |
|
|
231
|
+
| `thirdParty:createApp` | Register a new app |
|
|
232
|
+
| `thirdParty:getApp` | Get app details by ID |
|
|
233
|
+
| `thirdParty:updateApp` | Update an app |
|
|
234
|
+
| `thirdParty:deleteApp` | Request app deactivation |
|
|
235
|
+
| `thirdParty:listWebhooks` | List webhooks (paginated) |
|
|
236
|
+
| `thirdParty:createWebhook` | Create a new webhook |
|
|
237
|
+
| `thirdParty:getWebhook` | Get webhook details by ID |
|
|
238
|
+
| `thirdParty:updateWebhook` | Update a webhook |
|
|
239
|
+
| `thirdParty:deleteWebhook` | Delete a webhook |
|
|
240
|
+
| `thirdParty:rotateWebhookSigningKey` | Rotate webhook signing key |
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Token Amounts (bigint base units)
|
|
2
|
+
|
|
3
|
+
Frontier SDK v0.24.0 — imported from `@frontiertower/frontier-sdk` (the package root, **NOT** the `/ui-utils` subpath).
|
|
4
|
+
|
|
5
|
+
Since v0.23 all FND amounts are **bigint base units**. This module is the canonical `bigint <-> display-string` bridge that every FND-handling app depends on: wallet balances, `transfer*`/`swap` amounts, and the events security-deposit token amounts are all bigint, and these helpers convert to/from the human-readable strings you show in the UI or read from an input field.
|
|
6
|
+
|
|
7
|
+
## Exports (from the package root — `frontier-sdk/src/index.ts:26`)
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import {
|
|
11
|
+
parseAmount,
|
|
12
|
+
formatAmount,
|
|
13
|
+
FND_DECIMALS,
|
|
14
|
+
InvalidAmountError,
|
|
15
|
+
} from '@frontiertower/frontier-sdk';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
| Export | Signature | Source |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `FND_DECIMALS` | `const FND_DECIMALS: number` (= `6`) | `token-amount.ts:2` |
|
|
21
|
+
| `parseAmount` | `parseAmount(value: string, decimals = FND_DECIMALS): bigint` | `token-amount.ts:19` |
|
|
22
|
+
| `formatAmount` | `formatAmount(amount: bigint, decimals = FND_DECIMALS): string` | `token-amount.ts:40` |
|
|
23
|
+
| `InvalidAmountError` | `class InvalidAmountError extends Error` | `token-amount.ts:5` |
|
|
24
|
+
|
|
25
|
+
`FND_DECIMALS = 6` is the decimal precision of the Frontier Dollar (FND). Both helpers default to it, so for FND you never pass `decimals` explicitly; pass it only for non-FND tokens (read the on-chain `decimals` from chain config — see Notes).
|
|
26
|
+
|
|
27
|
+
## `parseAmount(value, decimals = 6) -> bigint`
|
|
28
|
+
|
|
29
|
+
Parses a plain decimal string into a bigint in base units.
|
|
30
|
+
|
|
31
|
+
- `'75.5'` -> `75500000n`
|
|
32
|
+
- `'100'` -> `100000000n`
|
|
33
|
+
- `'0.000001'` -> `1n`
|
|
34
|
+
|
|
35
|
+
Symbol-free and locale-free by design. It throws `InvalidAmountError` on:
|
|
36
|
+
|
|
37
|
+
- currency symbols (`'$10'`)
|
|
38
|
+
- thousands separators (`'1,000'`)
|
|
39
|
+
- comma decimals (`'10,5'`)
|
|
40
|
+
- empty / whitespace-only string
|
|
41
|
+
- trailing dot (`'10.'`)
|
|
42
|
+
- more fractional digits than `decimals` (e.g. `'1.1234567'` for 6-decimal FND)
|
|
43
|
+
|
|
44
|
+
The validation regex is `/^-?\d+(\.\d+)?$/`, so **a leading minus IS permitted and negatives parse**: `'-5'` -> `-5000000n`. Guard against negative amounts yourself if your flow requires non-negative values. Normalize locale input (`','` -> `'.'`) before calling.
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
let amount: bigint;
|
|
48
|
+
try {
|
|
49
|
+
amount = parseAmount(userInput); // throws InvalidAmountError on bad input
|
|
50
|
+
} catch (err) {
|
|
51
|
+
if (err instanceof InvalidAmountError) {
|
|
52
|
+
// surface a validation message to the user
|
|
53
|
+
}
|
|
54
|
+
throw err;
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## `formatAmount(amount, decimals = 6) -> string`
|
|
59
|
+
|
|
60
|
+
Formats a bigint base-unit amount into an exact, symbol-free decimal string.
|
|
61
|
+
|
|
62
|
+
- `75500000n` -> `'75.5'`
|
|
63
|
+
- `100000000n` -> `'100'`
|
|
64
|
+
- `1n` -> `'0.000001'`
|
|
65
|
+
- `-5000000n` -> `'-5'`
|
|
66
|
+
|
|
67
|
+
Full precision, trailing zeros trimmed, round-trips with `parseAmount`, negatives preserved. **The SDK never emits `'$'`** — display concerns (the `$` symbol, rounding, grouping separators) belong to the caller. Prepend the currency symbol yourself:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const display = `$${formatAmount(balance.fnd)}`; // '$75.5'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Canonical usage (read -> display, input -> write)
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import {
|
|
77
|
+
FrontierSDK,
|
|
78
|
+
formatAmount,
|
|
79
|
+
parseAmount,
|
|
80
|
+
} from '@frontiertower/frontier-sdk';
|
|
81
|
+
|
|
82
|
+
const wallet = sdk.getWallet();
|
|
83
|
+
|
|
84
|
+
// Read: getBalance() returns WalletBalance { total, fnd, internalFnd } — all bigint.
|
|
85
|
+
const balance = await wallet.getBalance();
|
|
86
|
+
const fndDisplay = formatAmount(balance.fnd); // e.g. '75.5' for the UI
|
|
87
|
+
|
|
88
|
+
// Write: parse the user's input to bigint, then pass it straight to the transfer.
|
|
89
|
+
const amount = parseAmount(userInput); // throws InvalidAmountError
|
|
90
|
+
await wallet.transferFrontierDollar(recipient, amount);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The same pattern applies to `transferInternalFrontierDollar`, `transferOverallFrontierDollar`, `swap`, and `quoteSwap` — all take `amount: bigint`. See `references/sdk/wallet.md`.
|
|
94
|
+
|
|
95
|
+
## Notes
|
|
96
|
+
|
|
97
|
+
- `getBalanceFormatted()` and the `WalletBalanceFormatted` interface were **REMOVED in v0.23** (along with the `wallet:getBalanceFormatted` permission). There is no SDK method that returns pre-formatted display strings — call `getBalance()` and format each bigint field locally with `formatAmount()`.
|
|
98
|
+
- Base units, not display strings, cross the SDK boundary: a balance of `100_000000n` is `'100'` FND, and `1n` is the smallest representable amount (`0.000001` FND).
|
|
99
|
+
- For **non-FND tokens** (e.g. the events deposit ERC-20 candidates), do not assume 6 decimals. The on-chain `decimals` come from chain config: `(await sdk.getChain().getCurrentChainConfig()).stableCoins[].decimals`. Pass that value as the `decimals` argument to `parseAmount`/`formatAmount`, or use the `baseUnits` string the SDK already provides (the events `DepositPreflightToken.baseUnits` is wrapped with `BigInt(...)` for `approveERC20`).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Shared SDK Types
|
|
2
|
+
|
|
3
|
+
Types used across multiple SDK modules.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Pagination
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
interface PaginatedResponse<T> {
|
|
11
|
+
count: number;
|
|
12
|
+
results: T[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface PaginatedParams {
|
|
16
|
+
limit?: number;
|
|
17
|
+
offset?: number;
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Most list methods accept `PaginatedParams` (or a superset) and return `PaginatedResponse<T>`.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Total Permissions Count
|
|
26
|
+
|
|
27
|
+
85 permissions across 10 modules. See each module's reference file for its specific permissions.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# UI Utilities
|
|
2
|
+
|
|
3
|
+
Import from `@frontiertower/frontier-sdk/ui-utils`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Detection
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
function isInFrontierApp(): boolean
|
|
11
|
+
```
|
|
12
|
+
Returns `true` if the window is embedded in an iframe (`window.self !== window.top`). Use to detect whether the app is running inside the Frontier Wallet host.
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
function getParentOrigin(): string | null
|
|
16
|
+
```
|
|
17
|
+
Returns the origin of the parent window (via `document.referrer` or `window.parent.location.origin`). Returns `null` if not in an iframe or origin cannot be determined.
|
|
18
|
+
|
|
19
|
+
## Standalone Fallback
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
function renderStandaloneMessage(container: HTMLElement, appName?: string): void
|
|
23
|
+
```
|
|
24
|
+
Renders a styled "Frontier Wallet Required" message into the given container element. Default `appName` is `'Frontier App'`. Directs users to `os.frontiertower.io` to install the app.
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
function createStandaloneHTML(appName?: string): string
|
|
28
|
+
```
|
|
29
|
+
Returns the same styled "Frontier Wallet Required" message as an HTML string (with gradient background). Default `appName` is `'Frontier App'`.
|
|
30
|
+
|
|
31
|
+
## Allowed Origins Constant
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
const ALLOWED_ORIGINS: string[] = [
|
|
35
|
+
'http://localhost:5173',
|
|
36
|
+
'https://sandbox.os.frontiertower.io',
|
|
37
|
+
'https://os.frontiertower.io',
|
|
38
|
+
];
|
|
39
|
+
```
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# User Module
|
|
2
|
+
|
|
3
|
+
**Trigger keywords:** user, profile, account, member, membership, auth, login, referral, invite, refer, signup, register, kyc, verify, identity, access control, gate, permission, name, person
|
|
4
|
+
|
|
5
|
+
Access via `sdk.getUser()`. Query user info, profiles, referrals, KYC, and access controls.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Methods
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
getDetails(): Promise<User>
|
|
13
|
+
```
|
|
14
|
+
Returns basic user info (id, email, name, active/superuser status). Permission: `user:getDetails`
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
getProfile(): Promise<UserProfile>
|
|
18
|
+
```
|
|
19
|
+
Returns detailed profile (social handles, preferences, community, notification settings). Permission: `user:getProfile`
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
getReferralOverview(): Promise<ReferralOverview>
|
|
23
|
+
```
|
|
24
|
+
Returns referral statistics (count, ranking, referral link/code). Permission: `user:getReferralOverview`
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
getReferralDetails(page?: number): Promise<PaginatedResponse<ReferralDetails>>
|
|
28
|
+
```
|
|
29
|
+
Returns paginated referral details. Permission: `user:getReferralDetails`
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
addUserContact(data: UserContactPayload): Promise<void>
|
|
33
|
+
```
|
|
34
|
+
Submit contact information for the current user. Permission: `user:addUserContact`
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
getOrCreateKyc(redirectUri?: string): Promise<KycStatusResponse>
|
|
38
|
+
```
|
|
39
|
+
Get or initiate KYC verification. Returns status and a KYC link if verification has been started. Permission: `user:getOrCreateKyc`
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
createSignupRequest(payload: CreateSignupRequestPayload): Promise<CreateSignupRequestResponse>
|
|
43
|
+
```
|
|
44
|
+
Submit a new membership signup request with crypto payment. Permission: `user:createSignupRequest`
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
getVerifiedAccessControls(): Promise<AccessControlsPayload>
|
|
48
|
+
```
|
|
49
|
+
Returns cryptographically verified access controls signed by the Frontier API server. The SDK verifies an ECDSA secp256k1 signature against hardcoded per-environment public keys inside the iframe. **Use this for all access-gating decisions** -- unsigned data from other SDK methods should not be trusted for feature gating. Throws if signature verification fails. Permission: `user:getVerifiedAccessControls`
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Types
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
interface User {
|
|
57
|
+
id: number;
|
|
58
|
+
email: string;
|
|
59
|
+
firstName: string;
|
|
60
|
+
lastName: string;
|
|
61
|
+
isActive: boolean;
|
|
62
|
+
dateJoined: string;
|
|
63
|
+
isSuperuser: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface UserProfile {
|
|
67
|
+
id: number;
|
|
68
|
+
user: number;
|
|
69
|
+
firstName: string;
|
|
70
|
+
lastName: string;
|
|
71
|
+
nickname: string;
|
|
72
|
+
profilePicture: string;
|
|
73
|
+
phoneNumber: string;
|
|
74
|
+
community: string;
|
|
75
|
+
communityName: string;
|
|
76
|
+
organization: string;
|
|
77
|
+
organizationRole: string;
|
|
78
|
+
socialSite: string;
|
|
79
|
+
socialHandle: string;
|
|
80
|
+
githubHandle: string;
|
|
81
|
+
currentWork: string;
|
|
82
|
+
notableWork: string;
|
|
83
|
+
receiveUpdates: boolean;
|
|
84
|
+
notificationCommunityEvent: boolean;
|
|
85
|
+
notificationTowerEvent: boolean;
|
|
86
|
+
notificationUpcomingEvent: boolean;
|
|
87
|
+
notificationTweetPicked: boolean;
|
|
88
|
+
notifyEventInvites: boolean;
|
|
89
|
+
optInSms: boolean;
|
|
90
|
+
howDidYouHearAboutUs: string;
|
|
91
|
+
braggingStatement: string;
|
|
92
|
+
contributionStatement: string;
|
|
93
|
+
hasUsablePassword: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
interface ReferralOverview {
|
|
97
|
+
referralCount: number;
|
|
98
|
+
ranking: number;
|
|
99
|
+
referralLink: string;
|
|
100
|
+
referralCode: string;
|
|
101
|
+
referredBy: string | null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
interface ReferralDetails {
|
|
105
|
+
name: string;
|
|
106
|
+
email: string;
|
|
107
|
+
referralDate: string;
|
|
108
|
+
reward: string;
|
|
109
|
+
status: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
interface UserContact {
|
|
113
|
+
email: string;
|
|
114
|
+
phone: string;
|
|
115
|
+
name: string;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
interface UserContactPayload {
|
|
119
|
+
contacts: UserContact[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
type KycStatus = 'not_started' | 'pending' | 'in_review' | 'approved' | 'rejected';
|
|
123
|
+
type TosStatus = 'pending' | 'approved';
|
|
124
|
+
|
|
125
|
+
interface KycStatusResponse {
|
|
126
|
+
status: KycStatus;
|
|
127
|
+
isApproved: boolean;
|
|
128
|
+
rejectionReason: string | null;
|
|
129
|
+
kycLinkId: string | null;
|
|
130
|
+
kycLink: string | null;
|
|
131
|
+
tosStatus: TosStatus | null;
|
|
132
|
+
tosLink: string | null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
interface CreateSignupRequestPayload {
|
|
136
|
+
subscriptionPlan: string;
|
|
137
|
+
subscriptionInterval: string;
|
|
138
|
+
firstName: string;
|
|
139
|
+
lastName: string;
|
|
140
|
+
email: string;
|
|
141
|
+
phoneNumber: string;
|
|
142
|
+
socialSite: string;
|
|
143
|
+
socialHandle: string;
|
|
144
|
+
currentWork: string;
|
|
145
|
+
howDidYouHearAboutUs: string;
|
|
146
|
+
braggingStatement: string;
|
|
147
|
+
contributionStatement: string;
|
|
148
|
+
billingFirstName: string;
|
|
149
|
+
billingLastName: string;
|
|
150
|
+
billingEmail: string;
|
|
151
|
+
billingPhoneNumber: string;
|
|
152
|
+
paymentProvider: 'crypto';
|
|
153
|
+
smartAccount: number;
|
|
154
|
+
community: string;
|
|
155
|
+
githubHandle?: string;
|
|
156
|
+
notableWork?: string;
|
|
157
|
+
referralCode?: string;
|
|
158
|
+
receiveUpdates?: boolean;
|
|
159
|
+
optInSms?: boolean;
|
|
160
|
+
organization?: string;
|
|
161
|
+
organizationRole?: string;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
interface CreateSignupRequestResponse {
|
|
165
|
+
subscriptionUuid: string;
|
|
166
|
+
paymentProvider: string;
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Access Controls Types
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
interface AccessControlsPayload {
|
|
174
|
+
smartAccountAddress: string | null;
|
|
175
|
+
email: string;
|
|
176
|
+
isSuperuser: boolean;
|
|
177
|
+
subscriptionStatus: string | null; // 'active' | 'canceled' | 'awaiting_approval' | null
|
|
178
|
+
subscriptionPlan: string | null;
|
|
179
|
+
subscriptionInterval: string | null;
|
|
180
|
+
subscriptionType: string | null; // 'crypto' | 'stripe' | 'grant' | 'office' | 'internship' | null
|
|
181
|
+
addOns: string[];
|
|
182
|
+
communities: string[];
|
|
183
|
+
managedCommunities: string[];
|
|
184
|
+
timestamp: string;
|
|
185
|
+
kid: string;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
interface SignedAccessControls {
|
|
189
|
+
accessControls: string; // Base64-encoded canonical JSON payload
|
|
190
|
+
stage: string; // API stage (e.g. 'production', 'sandbox')
|
|
191
|
+
signature: string; // Hex-encoded ECDSA signature (r||s, 128 hex chars)
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Permissions (8)
|
|
198
|
+
|
|
199
|
+
| Permission | Description |
|
|
200
|
+
|---|---|
|
|
201
|
+
| `user:getDetails` | Access current user details |
|
|
202
|
+
| `user:getProfile` | Access current user profile |
|
|
203
|
+
| `user:getReferralOverview` | Access referral statistics |
|
|
204
|
+
| `user:getReferralDetails` | Access detailed referral information |
|
|
205
|
+
| `user:addUserContact` | Add user contact information |
|
|
206
|
+
| `user:getOrCreateKyc` | Get or create KYC verification status |
|
|
207
|
+
| `user:createSignupRequest` | Submit membership signup request with crypto payment |
|
|
208
|
+
| `user:getVerifiedAccessControls` | Get cryptographically verified access controls |
|