frontier-os-app-builder 1.0.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.
Files changed (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -14
  3. package/agents/fos-executor.md +105 -39
  4. package/agents/fos-plan-checker.md +62 -25
  5. package/agents/fos-planner.md +80 -72
  6. package/agents/fos-researcher.md +26 -15
  7. package/agents/fos-verifier.md +96 -27
  8. package/bin/fos-tools.cjs +146 -42
  9. package/bin/install.js +8 -5
  10. package/commands/fos/add-feature.md +1 -2
  11. package/commands/fos/discuss.md +0 -1
  12. package/commands/fos/new-app.md +2 -4
  13. package/commands/fos/new-milestone.md +1 -1
  14. package/commands/fos/plan.md +0 -2
  15. package/package.json +7 -1
  16. package/references/app-patterns.md +128 -21
  17. package/references/deployment.md +40 -124
  18. package/references/module-index.md +32 -0
  19. package/references/sdk/chain.md +92 -0
  20. package/references/sdk/communities.md +159 -0
  21. package/references/sdk/events.md +212 -0
  22. package/references/sdk/init.md +126 -0
  23. package/references/sdk/navigation.md +49 -0
  24. package/references/sdk/offices.md +76 -0
  25. package/references/sdk/partnerships.md +111 -0
  26. package/references/sdk/storage.md +44 -0
  27. package/references/sdk/thirdparty.md +240 -0
  28. package/references/sdk/token-amount.md +99 -0
  29. package/references/sdk/types.md +27 -0
  30. package/references/sdk/ui-utils.md +39 -0
  31. package/references/sdk/user.md +208 -0
  32. package/references/sdk/wallet.md +334 -0
  33. package/references/verification-rules.md +111 -50
  34. package/templates/app/frontier-services.tsx +871 -0
  35. package/templates/app/layout-standalone.tsx +8 -0
  36. package/templates/app/layout.tsx +19 -9
  37. package/templates/app/package-standalone.json +35 -0
  38. package/templates/app/package.json +2 -1
  39. package/templates/app/public/favicon.svg +3 -0
  40. package/templates/app/sdk-context.tsx +7 -9
  41. package/templates/app/sdk-services.tsx +98 -0
  42. package/templates/app/vercel-standalone.json +5 -0
  43. package/templates/app/vercel.json +8 -95
  44. package/templates/state/plan.md +32 -14
  45. package/templates/state/requirements.md +1 -1
  46. package/templates/state/roadmap.md +57 -24
  47. package/templates/state/summary.md +27 -30
  48. package/workflows/add-feature.md +6 -1
  49. package/workflows/discuss.md +126 -11
  50. package/workflows/execute-plan.md +21 -14
  51. package/workflows/execute.md +204 -24
  52. package/workflows/new-app.md +64 -23
  53. package/workflows/new-milestone.md +10 -3
  54. package/workflows/plan.md +16 -5
  55. package/workflows/ship.md +91 -34
  56. package/workflows/status.md +1 -2
  57. package/references/module-inference.md +0 -349
  58. package/references/sdk-surface.md +0 -1622
  59. package/templates/app/main-simple.tsx +0 -19
  60. package/templates/state/manifest.json +0 -11
@@ -0,0 +1,159 @@
1
+ # Communities Module
2
+
3
+ **Trigger keywords:** community, group, team, club, internship, intern, cohort, reassign, transfer member, collective, society
4
+
5
+ Access via `sdk.getCommunities()`. Manage communities, internship passes, and member reassignment requests.
6
+
7
+ Community listing is public. Internship passes require authentication, an active subscription, and community manager status. Reassign requests require authentication; creating requires managing the member's current community, accepting requires managing the target community. Superusers can access everything.
8
+
9
+ ---
10
+
11
+ ## Methods
12
+
13
+ ```typescript
14
+ listCommunities(payload?: ListCommunitiesParams): Promise<PaginatedResponse<Community>>
15
+ ```
16
+ List all visible communities, paginated. Permission: `communities:listCommunities`
17
+
18
+ ```typescript
19
+ getCommunity(payload: { idOrSlug: string | number }): Promise<Community>
20
+ ```
21
+ Get a community by numeric ID or slug string. Permission: `communities:getCommunity`
22
+
23
+ ```typescript
24
+ createInternshipPass(payload: CreateInternshipPassRequest): Promise<InternshipPass>
25
+ ```
26
+ Create an internship pass. Auto-creates an inactive account if the user does not exist. Permission: `communities:createInternshipPass`
27
+
28
+ ```typescript
29
+ listInternshipPasses(payload?: ListInternshipPassesParams): Promise<PaginatedResponse<InternshipPass>>
30
+ ```
31
+ List internship passes for managed communities. Active only by default; set `includeRevoked: true` to include revoked. Permission: `communities:listInternshipPasses`
32
+
33
+ ```typescript
34
+ getInternshipPass(payload: { id: number }): Promise<InternshipPass>
35
+ ```
36
+ Get an internship pass by ID. Permission: `communities:getInternshipPass`
37
+
38
+ ```typescript
39
+ revokeInternshipPass(payload: { id: number }): Promise<void>
40
+ ```
41
+ Revoke an internship pass. Cannot revoke an already-revoked pass. Permission: `communities:revokeInternshipPass`
42
+
43
+ ```typescript
44
+ createReassignRequest(payload: CreateReassignRequestPayload): Promise<ReassignRequest>
45
+ ```
46
+ Request to move a member to a different community. Caller must manage the member's current community. Permission: `communities:createReassignRequest`
47
+
48
+ ```typescript
49
+ listReassignRequests(payload?: ListReassignRequestsParams): Promise<PaginatedResponse<ReassignRequest>>
50
+ ```
51
+ List pending reassign requests visible to the caller. Permission: `communities:listReassignRequests`
52
+
53
+ ```typescript
54
+ getReassignRequest(payload: { id: number }): Promise<ReassignRequest>
55
+ ```
56
+ Get a reassign request by ID. Permission: `communities:getReassignRequest`
57
+
58
+ ```typescript
59
+ acceptReassignRequest(payload: { id: number }): Promise<ReassignRequest>
60
+ ```
61
+ Accept a reassign request. Moves the member to the target community. Only target community managers (or superusers) can accept. Permission: `communities:acceptReassignRequest`
62
+
63
+ ```typescript
64
+ rejectReassignRequest(payload: { id: number }): Promise<void>
65
+ ```
66
+ Reject a reassign request. Only pending requests can be rejected. Permission: `communities:rejectReassignRequest`
67
+
68
+ ---
69
+
70
+ ## Types
71
+
72
+ ```typescript
73
+ interface Community {
74
+ id: number;
75
+ name: string;
76
+ description: string;
77
+ slug: string;
78
+ iconName: string;
79
+ splashVideo: string | null;
80
+ }
81
+
82
+ interface ListCommunitiesParams {
83
+ limit?: number;
84
+ offset?: number;
85
+ }
86
+
87
+ type InternshipPassStatus = 'active' | 'revoked';
88
+
89
+ interface InternshipPass {
90
+ id: number;
91
+ email: string;
92
+ firstName: string;
93
+ lastName: string;
94
+ community: number;
95
+ communityName: string;
96
+ status: InternshipPassStatus;
97
+ createdAt: string;
98
+ revokedAt: string | null;
99
+ updatedAt: string;
100
+ }
101
+
102
+ interface CreateInternshipPassRequest {
103
+ email: string;
104
+ firstName: string;
105
+ lastName: string;
106
+ community: number;
107
+ }
108
+
109
+ interface ListInternshipPassesParams {
110
+ limit?: number;
111
+ offset?: number;
112
+ includeRevoked?: boolean;
113
+ }
114
+
115
+ type ReassignRequestStatus = 'pending' | 'accepted' | 'rejected';
116
+
117
+ interface ReassignRequest {
118
+ id: number;
119
+ requester: number;
120
+ requesterEmail: string;
121
+ member: number;
122
+ memberEmail: string;
123
+ targetCommunity: number;
124
+ targetCommunityName: string;
125
+ status: ReassignRequestStatus;
126
+ createdAt: string;
127
+ resolvedAt: string | null;
128
+ resolvedBy: number | null;
129
+ resolvedByEmail: string | null;
130
+ }
131
+
132
+ interface CreateReassignRequestPayload {
133
+ memberEmail: string;
134
+ targetCommunity: number;
135
+ }
136
+
137
+ interface ListReassignRequestsParams {
138
+ limit?: number;
139
+ offset?: number;
140
+ }
141
+ ```
142
+
143
+ ---
144
+
145
+ ## Permissions (11)
146
+
147
+ | Permission | Description |
148
+ |---|---|
149
+ | `communities:listCommunities` | List all visible communities (paginated) |
150
+ | `communities:getCommunity` | Get a community by ID or slug |
151
+ | `communities:createInternshipPass` | Create an internship pass for a managed community |
152
+ | `communities:listInternshipPasses` | List internship passes for managed communities |
153
+ | `communities:getInternshipPass` | Retrieve an internship pass by ID |
154
+ | `communities:revokeInternshipPass` | Revoke an internship pass |
155
+ | `communities:createReassignRequest` | Create a member reassignment request |
156
+ | `communities:listReassignRequests` | List pending reassignment requests |
157
+ | `communities:getReassignRequest` | Retrieve a reassignment request by ID |
158
+ | `communities:acceptReassignRequest` | Accept a reassignment request (moves member) |
159
+ | `communities:rejectReassignRequest` | Reject a reassignment request |
@@ -0,0 +1,212 @@
1
+ # Events Module
2
+
3
+ **Trigger keywords:** event, meetup, gathering, calendar, schedule, room, booking, reserve, reservation, space, venue, location, conference, meeting, coworking
4
+
5
+ Access via `sdk.getEvents()`. Manage events, locations (event spaces and rooms), and room bookings.
6
+
7
+ ---
8
+
9
+ ## Methods
10
+
11
+ ```typescript
12
+ listEvents(payload?: ListEventsParams): Promise<PaginatedResponse<Event>>
13
+ ```
14
+ List active events with optional filters (search, type, location, date range). Permission: `events:listEvents`
15
+
16
+ ```typescript
17
+ createEvent(payload: CreateEventRequest): Promise<Event>
18
+ ```
19
+ Create a new event. Permission: `events:createEvent`
20
+
21
+ ```typescript
22
+ addEventHost(payload: { eventId: number; email: string }): Promise<Event>
23
+ ```
24
+ Add a co-host to an event. Only the primary host can add co-hosts, and only to upcoming events. Permission: `events:addEventHost`
25
+
26
+ ```typescript
27
+ listLocations(payload?: ListLocationsParams): Promise<Location[]>
28
+ ```
29
+ List available locations. Returns an array (not paginated). Optional `locationType` filter. Permission: `events:listLocations`
30
+
31
+ ```typescript
32
+ listRoomBookings(payload?: ListRoomBookingsParams): Promise<PaginatedResponse<RoomBooking>>
33
+ ```
34
+ List approved room bookings with optional filters. Permission: `events:listRoomBookings`
35
+
36
+ ```typescript
37
+ createRoomBooking(payload: CreateRoomBookingRequest): Promise<RoomBooking>
38
+ ```
39
+ Create a room booking. Location must be of type `'room'`. Permission: `events:createRoomBooking`
40
+
41
+ ```typescript
42
+ getCryptoDepositPreflight(payload: { eventId: number }): Promise<DepositPreflight>
43
+ ```
44
+ Preflight an event's FND security deposit. Host only, read-only. Returns the spender plus candidate ERC-20 tokens (iFND first, then FND) with on-chain decimals and base-unit amounts so you can approve the allowance BEFORE placing the deposit. Throws if not authenticated, not the host, or no deposit is required. Permission: `events:getCryptoDepositPreflight`
45
+
46
+ ```typescript
47
+ placeCryptoDeposit(payload: { eventId: number }): Promise<DepositResult>
48
+ ```
49
+ Place the FND security deposit. The backend `transferFrom`s the stablecoin from the member's smart account into treasury; the member must first approve the allowance to the preflight `spender` via `getWallet().approveERC20(token.address, spender, BigInt(token.baseUnits))`. Returns `status: 'secured'` (`reference` is the tx hash) or `'awaiting_payment'` (read `statusReason`, fix, retry). Host only. Permission: `events:placeCryptoDeposit`
50
+
51
+ **Canonical 3-step deposit flow** (host only):
52
+ ```typescript
53
+ // 1. Preflight — discover the spender + candidate tokens (iFND first, then FND)
54
+ const { spender, tokens } = await sdk.getEvents().getCryptoDepositPreflight({ eventId: 42 });
55
+ const token = tokens[0]; // prefer iFND; fall back to tokens[1] (FND) if the member lacks iFND
56
+ // 2. Approve the allowance to the spender (on-chain; the member confirms in the wallet)
57
+ await sdk.getWallet().approveERC20(token.address, spender, BigInt(token.baseUnits));
58
+ // 3. Place the deposit — the backend transferFroms it into treasury
59
+ const result = await sdk.getEvents().placeCryptoDeposit({ eventId: 42 });
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Types
65
+
66
+ ```typescript
67
+ type EventType = 'public' | 'members_plus_one' | 'members_only' | 'community_only';
68
+ type EventService = 'luma' | 'private' | 'test';
69
+ type ReviewStatus = 'not_required' | 'approved' | 'rejected' | 'pending';
70
+ type EventStatus = 'active' | 'suspended' | 'archived';
71
+ type LocationType = 'event_space' | 'room';
72
+
73
+ // Compact deposit status on the Event payload (host UI gating). 7 values.
74
+ type DepositStatus = 'not_required' | 'required' | 'pending' | 'secured' | 'released' | 'withheld' | 'failed';
75
+
76
+ // Raw status returned by placeCryptoDeposit. 6 values — has 'awaiting_payment' + 'grant', lacks 'not_required'/'required'/'pending'.
77
+ type CryptoDepositStatus = 'secured' | 'awaiting_payment' | 'grant' | 'released' | 'withheld' | 'failed';
78
+
79
+ interface Event {
80
+ id: number;
81
+ name: string;
82
+ description: string;
83
+ eventType: EventType;
84
+ eventService: EventService;
85
+ host: string;
86
+ community: number | null;
87
+ startsAt: string;
88
+ endsAt: string;
89
+ coverImage: string | null;
90
+ eventId: string;
91
+ location: string;
92
+ locationName: string;
93
+ displayLocation: string;
94
+ url: string;
95
+ additionalHosts: string[];
96
+ color: string;
97
+ reviewStatus: ReviewStatus;
98
+ status: EventStatus;
99
+ isHost?: boolean; // True iff the requesting user is this event's host (the user the deposit endpoints authorize)
100
+ deposit?: EventDeposit | null; // Read-only security-deposit summary, null when no deposit row
101
+ }
102
+
103
+ interface ListEventsParams {
104
+ search?: string;
105
+ eventType?: EventType;
106
+ locationType?: LocationType;
107
+ locationId?: string;
108
+ date?: string; // YYYY-MM-DD
109
+ startDate?: string; // YYYY-MM-DD
110
+ endDate?: string; // YYYY-MM-DD
111
+ page?: number;
112
+ }
113
+
114
+ interface CreateEventRequest {
115
+ name: string;
116
+ eventType: EventType;
117
+ startsAt: string; // ISO 8601
118
+ endsAt: string; // ISO 8601
119
+ location: string; // readable_id slug
120
+ description?: string;
121
+ coverImage?: string; // Base64 data URI
122
+ additionalHosts?: string[];
123
+ color?: string; // Hex color code
124
+ }
125
+
126
+ interface Location {
127
+ id: number;
128
+ owner: number | null;
129
+ readableId: string;
130
+ name: string;
131
+ maxCapacity: number;
132
+ description: string;
133
+ directions: string;
134
+ locationType: LocationType;
135
+ warmupBuffer: string; // e.g. "00:10:00"
136
+ cooldownBuffer: string; // e.g. "00:15:00"
137
+ openBooking: boolean;
138
+ floorLocation: string;
139
+ }
140
+
141
+ interface ListLocationsParams {
142
+ locationType?: LocationType;
143
+ }
144
+
145
+ interface RoomBooking {
146
+ id: number;
147
+ startsAt: string;
148
+ endsAt: string;
149
+ location: string;
150
+ }
151
+
152
+ interface ListRoomBookingsParams {
153
+ locationId?: string;
154
+ date?: string; // YYYY-MM-DD
155
+ startDate?: string; // YYYY-MM-DD
156
+ endDate?: string; // YYYY-MM-DD
157
+ page?: number;
158
+ }
159
+
160
+ interface CreateRoomBookingRequest {
161
+ startsAt: string; // ISO 8601
162
+ endsAt: string; // ISO 8601
163
+ location: string; // readable_id (must be room type)
164
+ }
165
+
166
+ interface EventDeposit {
167
+ status: DepositStatus;
168
+ amount: number; // snapshotted deposit amount in `currency` (e.g. 400 for the FND rail)
169
+ currency: string; // e.g. "usd"
170
+ }
171
+
172
+ interface DepositPreflightToken {
173
+ key: string; // e.g. "ifnd_token" or "fnd_token"
174
+ address: string; // ERC-20 contract to approve the allowance on
175
+ decimals: number; // on-chain token decimals (read from the contract, never assumed)
176
+ baseUnits: string; // deposit amount in this token's base units, as a decimal string (wrap in BigInt() for approveERC20)
177
+ }
178
+
179
+ interface DepositPreflight {
180
+ spender: string; // address to approve the allowance to (treasury) — never hardcode it
181
+ network: string; // e.g. "base" (prod) or "base_sepolia" (sandbox)
182
+ amount: string; // deposit amount in `currency`, as a decimal string (e.g. "400.00")
183
+ currency: string; // e.g. "usd"
184
+ tokens: DepositPreflightToken[]; // candidate tokens in preference order: iFND first, then FND
185
+ }
186
+
187
+ interface DepositResult {
188
+ provider: 'crypto'; // always 'crypto' on this rail
189
+ status: CryptoDepositStatus;
190
+ amount: string; // deposit amount in `currency`, as a decimal string
191
+ currency: string; // e.g. "usd"
192
+ reference: string; // on-chain tx hash when secured; empty otherwise
193
+ statusReason: string; // human-readable reason when not secured (e.g. insufficient iFND/FND allowance or balance)
194
+ }
195
+ ```
196
+
197
+ > **Deposit notes:** `DepositStatus` (7 values, carried on the `Event` payload) DIFFERS from `CryptoDepositStatus` (6 values, returned by `placeCryptoDeposit` — it adds `awaiting_payment` + `grant` and drops `not_required`/`required`/`pending`). `DepositPreflightToken.baseUnits` is a decimal STRING — wrap it via `BigInt()` for `approveERC20`. Never hardcode `spender` or token addresses, and read on-chain `decimals` rather than assuming 6.
198
+
199
+ ---
200
+
201
+ ## Permissions (8)
202
+
203
+ | Permission | Description |
204
+ |---|---|
205
+ | `events:listEvents` | List events with optional filters (paginated) |
206
+ | `events:createEvent` | Create a new event |
207
+ | `events:addEventHost` | Add a co-host to an event |
208
+ | `events:listLocations` | List available locations (event spaces and rooms) |
209
+ | `events:listRoomBookings` | List room bookings (paginated) |
210
+ | `events:createRoomBooking` | Create a room booking |
211
+ | `events:getCryptoDepositPreflight` | Preflight an event's FND security deposit (spender, candidate tokens, amounts) before approving the allowance |
212
+ | `events:placeCryptoDeposit` | Place an event's FND security deposit (backend transferFrom from the member's smart account) |
@@ -0,0 +1,126 @@
1
+ # SDK Initialization & Core Protocol
2
+
3
+ Frontier SDK v0.24.0 — `@frontiertower/frontier-sdk`
4
+
5
+ Import paths:
6
+ - `@frontiertower/frontier-sdk` -- main SDK class and access modules
7
+ - `@frontiertower/frontier-sdk/ui-utils` -- detection and standalone helpers
8
+
9
+ The package **root** also exports the bigint token-amount helpers `parseAmount`, `formatAmount`, `FND_DECIMALS`, and `InvalidAmountError` (from `@frontiertower/frontier-sdk`, **not** `/ui-utils`) — the canonical bridge for displaying and parsing the now-`bigint` FND amounts. See [`token-amount.md`](./token-amount.md).
10
+
11
+ ---
12
+
13
+ ## Class: `FrontierSDK`
14
+
15
+ ```typescript
16
+ import { FrontierSDK } from '@frontiertower/frontier-sdk';
17
+ ```
18
+
19
+ ### Constructor
20
+
21
+ ```typescript
22
+ const sdk = new FrontierSDK();
23
+ ```
24
+
25
+ On construction the SDK:
26
+ 1. Instantiates all ten access modules (wallet, storage, chain, user, partnerships, thirdParty, communities, events, offices, navigation).
27
+ 2. Registers a `window.addEventListener('message', ...)` listener that routes `SDKResponse` messages from `window.parent`.
28
+ 3. Sends an `{ type: 'app:ready', payload: null }` postMessage to `window.parent` to notify the host that the app iframe is ready.
29
+
30
+ ### `destroy(): void`
31
+
32
+ Call when the app is being torn down. Removes the message event listener, calls `this.navigation.destroy()` to clean up deep-link listeners, and clears all pending request promises.
33
+
34
+ ### Internal: `request(type: string, payload?: any): Promise<any>`
35
+
36
+ Used by all access classes. Sends an `SDKRequest` via `window.parent.postMessage` and returns a promise that resolves/rejects when the host responds. Requests time out after **30 000 ms**.
37
+
38
+ ## PostMessage Protocol Types
39
+
40
+ ```typescript
41
+ interface SDKRequest {
42
+ type: string; // e.g. 'wallet:getBalance'
43
+ requestId: string; // `${Date.now()}-${incrementingId}`
44
+ payload?: any;
45
+ }
46
+
47
+ interface SDKResponse {
48
+ type: 'response' | 'error';
49
+ requestId: string;
50
+ result?: any;
51
+ error?: string;
52
+ }
53
+ ```
54
+
55
+ ## Module Getters
56
+
57
+ | Getter | Returns | Module |
58
+ |---|---|---|
59
+ | `sdk.getWallet()` | `WalletAccess` | Wallet |
60
+ | `sdk.getStorage()` | `StorageAccess` | Storage |
61
+ | `sdk.getChain()` | `ChainAccess` | Chain |
62
+ | `sdk.getUser()` | `UserAccess` | User |
63
+ | `sdk.getPartnerships()` | `PartnershipsAccess` | Partnerships |
64
+ | `sdk.getThirdParty()` | `ThirdPartyAccess` | Third-Party |
65
+ | `sdk.getCommunities()` | `CommunitiesAccess` | Communities |
66
+ | `sdk.getEvents()` | `EventsAccess` | Events |
67
+ | `sdk.getOffices()` | `OfficesAccess` | Offices |
68
+ | `sdk.getNavigation()` | `NavigationAccess` | Navigation |
69
+
70
+ ---
71
+
72
+ ## Security
73
+
74
+ ### Allowed Origins
75
+
76
+ The SDK defines three allowed Frontier Wallet origins. Apps should only accept messages from these:
77
+
78
+ | Environment | Origin |
79
+ |---|---|
80
+ | Development | `http://localhost:5173` |
81
+ | Sandbox | `https://sandbox.os.frontiertower.io` |
82
+ | Production | `https://os.frontiertower.io` |
83
+
84
+ ### Access Controls Verification
85
+
86
+ The `user:getVerifiedAccessControls` method provides a tamper-proof way to verify user access. The flow:
87
+
88
+ 1. The PWA host relays a `SignedAccessControls` envelope from the Frontier API server.
89
+ 2. The SDK decodes the Base64 payload, computes its SHA-256 hash, and verifies the ECDSA secp256k1 signature against a hardcoded public key for the current environment stage.
90
+ 3. If the signature is valid, the decoded `AccessControlsPayload` is returned.
91
+ 4. If invalid, the method throws -- the app should deny access.
92
+
93
+ Supported stages and their public keys (uncompressed secp256k1, hex):
94
+
95
+ | Stage(s) | Key |
96
+ |---|---|
97
+ | `test` | `04aab6c393...` (test-only key) |
98
+ | `development`, `local`, `sandbox`, `staging` | `04dc3ab0e1...` (shared dev/sandbox key) |
99
+ | `production` | `045d1a0f9c...` (production key) |
100
+
101
+ **Rule: Always use `getVerifiedAccessControls()` for access-gating decisions.** Do not trust unsigned user data from other SDK methods for gating features, content, or permissions.
102
+
103
+ ### PostMessage Security
104
+
105
+ - The SDK sends requests to `window.parent` with `'*'` as the target origin.
106
+ - The SDK only processes responses where `event.source === window.parent`.
107
+ - Requests auto-expire after 30 seconds.
108
+
109
+ ---
110
+
111
+ ## Wildcard Permissions
112
+
113
+ Each module supports a wildcard permission that grants access to all methods in that module:
114
+
115
+ | Wildcard | Grants |
116
+ |---|---|
117
+ | `wallet:*` | All wallet permissions |
118
+ | `storage:*` | All storage permissions |
119
+ | `chain:*` | All chain permissions |
120
+ | `user:*` | All user permissions |
121
+ | `partnerships:*` | All partnerships permissions |
122
+ | `thirdParty:*` | All third-party permissions |
123
+ | `communities:*` | All communities permissions |
124
+ | `events:*` | All events permissions |
125
+ | `offices:*` | All offices permissions |
126
+ | `navigation:*` | All navigation permissions |
@@ -0,0 +1,49 @@
1
+ # Navigation Module
2
+
3
+ **Trigger keywords:** navigate, deep link, deeplink, open app, app link, cross-app, redirect, launch app, inter-app
4
+
5
+ Access via `sdk.getNavigation()`. App-to-app deep linking. Allows apps to navigate to other Frontier OS apps and receive incoming deep link data.
6
+
7
+ ---
8
+
9
+ ## Methods
10
+
11
+ ```typescript
12
+ openApp(appId: string, options?: NavigationOpenAppOptions): Promise<void>
13
+ ```
14
+ Navigate the host to another app in the Frontier OS ecosystem. `appId` is the target app ID from the Frontier app registry. `options.path` provides an optional deep link path for the target app. `options.params` provides optional key-value params for the target app. Permission: `navigation:openApp`
15
+
16
+ ```typescript
17
+ close(): Promise<void>
18
+ ```
19
+ Close the current app and return to the previous screen. Permission: `navigation:close`
20
+
21
+ ```typescript
22
+ onDeepLink(callback: (data: DeepLinkData) => void): () => void
23
+ ```
24
+ Register a callback for incoming deep link data. Called when this app was opened via another app's `openApp()` call. Returns an unsubscribe function. No permission required (passive listener).
25
+
26
+ ---
27
+
28
+ ## Types
29
+
30
+ ```typescript
31
+ interface NavigationOpenAppOptions {
32
+ path?: string;
33
+ params?: Record<string, string>;
34
+ }
35
+
36
+ interface DeepLinkData {
37
+ path?: string;
38
+ params?: Record<string, string>;
39
+ }
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Permissions (2)
45
+
46
+ | Permission | Description |
47
+ |---|---|
48
+ | `navigation:openApp` | Navigate to another app |
49
+ | `navigation:close` | Close current app |
@@ -0,0 +1,76 @@
1
+ # Offices Module
2
+
3
+ **Trigger keywords:** office, access pass, building, door, entry, visitor, check-in, checkin, physical access, facility
4
+
5
+ Access via `sdk.getOffices()`. Manage office access passes for membership contracts.
6
+
7
+ All endpoints require authentication, an active subscription, and manager status on the membership contract's organization (or superuser).
8
+
9
+ ---
10
+
11
+ ## Methods
12
+
13
+ ```typescript
14
+ createAccessPass(payload: CreateAccessPassRequest): Promise<AccessPass>
15
+ ```
16
+ Create an access pass for a membership contract. Auto-creates an inactive account if the user does not exist. Each user can only have one active pass per contract. Permission: `offices:createAccessPass`
17
+
18
+ ```typescript
19
+ listAccessPasses(payload?: ListAccessPassesParams): Promise<PaginatedResponse<AccessPass>>
20
+ ```
21
+ List access passes for contracts the user manages. Active only by default; set `includeRevoked: true` for all. Ordered newest first. Permission: `offices:listAccessPasses`
22
+
23
+ ```typescript
24
+ getAccessPass(payload: { id: number }): Promise<AccessPass>
25
+ ```
26
+ Get an access pass by ID. Permission: `offices:getAccessPass`
27
+
28
+ ```typescript
29
+ revokeAccessPass(payload: { id: number }): Promise<void>
30
+ ```
31
+ Revoke an access pass. Cannot revoke an already-revoked pass. Permission: `offices:revokeAccessPass`
32
+
33
+ ---
34
+
35
+ ## Types
36
+
37
+ ```typescript
38
+ type AccessPassStatus = 'active' | 'revoked';
39
+
40
+ interface AccessPass {
41
+ id: number;
42
+ email: string;
43
+ firstName: string;
44
+ lastName: string;
45
+ status: AccessPassStatus;
46
+ membershipContract: number;
47
+ contractReference: string;
48
+ createdAt: string;
49
+ revokedAt: string | null;
50
+ updatedAt: string;
51
+ }
52
+
53
+ interface CreateAccessPassRequest {
54
+ email: string;
55
+ firstName: string;
56
+ lastName: string;
57
+ membershipContract: number;
58
+ }
59
+
60
+ interface ListAccessPassesParams {
61
+ limit?: number;
62
+ offset?: number;
63
+ includeRevoked?: boolean;
64
+ }
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Permissions (4)
70
+
71
+ | Permission | Description |
72
+ |---|---|
73
+ | `offices:createAccessPass` | Create an access pass for a membership contract |
74
+ | `offices:listAccessPasses` | List access passes for managed contracts (paginated) |
75
+ | `offices:getAccessPass` | Retrieve an access pass by ID |
76
+ | `offices:revokeAccessPass` | Revoke an access pass |