@seeka-labs/cli-apps 3.8.10 → 3.9.1
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/dist/index.cjs +821 -612
- package/dist/init-template.zip +0 -0
- package/package.json +3 -2
- package/dist/ai-context/common/README.md +0 -110
- package/dist/ai-context/common/architecture/overview.md +0 -140
- package/dist/ai-context/common/guides/common-patterns.md +0 -471
- package/dist/ai-context/common/guides/data-flow.md +0 -455
- package/dist/ai-context/common/guides/getting-started.md +0 -349
- package/dist/ai-context/common/guides/testing.md +0 -592
- package/dist/ai-context/common/reference/cli-commands.md +0 -231
- package/dist/ai-context/common/reference/config-schema.md +0 -345
- package/dist/ai-context/common/reference/sdk-api.md +0 -445
- package/dist/ai-context/public/architecture/app-structure.md +0 -385
- package/dist/index.cjs.map +0 -7
- package/dist/init-template/.github/workflows/deploy-azurefunc.yml +0 -198
- package/dist/init-template/.gitlab-ci.yml +0 -67
- package/dist/init-template/.nvmrc +0 -1
- package/dist/init-template/AGENTS.md +0 -99
- package/dist/init-template/README.azurefunc.md +0 -238
- package/dist/init-template/app/.eslintrc.cjs +0 -13
- package/dist/init-template/app/browser/README.md +0 -1
- package/dist/init-template/app/browser/package.json +0 -36
- package/dist/init-template/app/browser/scripts/esbuild/build-browser-plugin.mjs +0 -130
- package/dist/init-template/app/browser/scripts/esbuild/plugins/importAsGlobals.mjs +0 -39
- package/dist/init-template/app/browser/src/browser.ts +0 -12
- package/dist/init-template/app/browser/src/plugin/index.ts +0 -61
- package/dist/init-template/app/browser/tsconfig.json +0 -34
- package/dist/init-template/app/lib/package.json +0 -46
- package/dist/init-template/app/lib/src/index.ts +0 -4
- package/dist/init-template/app/lib/src/models/index.ts +0 -29
- package/dist/init-template/app/lib/src/validation/index.ts +0 -14
- package/dist/init-template/app/lib/tsconfig.json +0 -22
- package/dist/init-template/app/server-azurefunc/.eslintrc.cjs +0 -4
- package/dist/init-template/app/server-azurefunc/.funcignore +0 -20
- package/dist/init-template/app/server-azurefunc/README.md +0 -105
- package/dist/init-template/app/server-azurefunc/host.json +0 -31
- package/dist/init-template/app/server-azurefunc/local.settings.template.json +0 -30
- package/dist/init-template/app/server-azurefunc/package.json +0 -68
- package/dist/init-template/app/server-azurefunc/scripts/build.mjs +0 -67
- package/dist/init-template/app/server-azurefunc/scripts/dev-queue-setup.js +0 -55
- package/dist/init-template/app/server-azurefunc/src/app/api/router.ts +0 -15
- package/dist/init-template/app/server-azurefunc/src/app/api/routes/getInstallationSettings.ts +0 -13
- package/dist/init-template/app/server-azurefunc/src/app/api/routes/setInstallationSettings.ts +0 -35
- package/dist/init-template/app/server-azurefunc/src/app/jobs/index.ts +0 -61
- package/dist/init-template/app/server-azurefunc/src/app/logging/index.ts +0 -4
- package/dist/init-template/app/server-azurefunc/src/app/models/index.ts +0 -12
- package/dist/init-template/app/server-azurefunc/src/app/services/activites.ts +0 -8
- package/dist/init-template/app/server-azurefunc/src/functions/healthCheck.ts +0 -19
- package/dist/init-template/app/server-azurefunc/src/functions/seekaAppWebhook.ts +0 -204
- package/dist/init-template/app/server-azurefunc/src/functions/trackActivityQueueHandler.ts +0 -48
- package/dist/init-template/app/server-azurefunc/src/functions/ui.ts +0 -49
- package/dist/init-template/app/server-azurefunc/tsconfig.json +0 -24
- package/dist/init-template/app/ui/README.md +0 -40
- package/dist/init-template/app/ui/index.html +0 -21
- package/dist/init-template/app/ui/package.json +0 -72
- package/dist/init-template/app/ui/public/favicon.ico +0 -0
- package/dist/init-template/app/ui/scripts/copy-output.mjs +0 -30
- package/dist/init-template/app/ui/src/App.tsx +0 -72
- package/dist/init-template/app/ui/src/assets/app-icon.svg +0 -1
- package/dist/init-template/app/ui/src/components/setup/steps/complete/index.tsx +0 -32
- package/dist/init-template/app/ui/src/components/setup/steps/first/index.tsx +0 -27
- package/dist/init-template/app/ui/src/components/setup/steps/index.tsx +0 -22
- package/dist/init-template/app/ui/src/components/setup/steps/second/index.tsx +0 -38
- package/dist/init-template/app/ui/src/index.tsx +0 -45
- package/dist/init-template/app/ui/src/routes/home/index.tsx +0 -21
- package/dist/init-template/app/ui/src/vite-env.d.ts +0 -13
- package/dist/init-template/app/ui/tsconfig.json +0 -35
- package/dist/init-template/app/ui/tsconfig.node.json +0 -10
- package/dist/init-template/app/ui/vite.config.mts +0 -48
- package/dist/init-template/package.json +0 -46
- package/dist/init-template/tsconfig.json +0 -24
|
@@ -1,349 +0,0 @@
|
|
|
1
|
-
# Getting Started: Extending Your Seeka App
|
|
2
|
-
|
|
3
|
-
This guide explains how to extend a scaffolded Seeka app to add custom functionality.
|
|
4
|
-
|
|
5
|
-
## Prerequisites
|
|
6
|
-
|
|
7
|
-
- A scaffolded Seeka app (created via `npx @seeka-labs/cli-apps init`)
|
|
8
|
-
- Node.js 18+ installed
|
|
9
|
-
- Yarn package manager
|
|
10
|
-
- Azure Functions Core Tools (for local development)
|
|
11
|
-
|
|
12
|
-
## Understanding the Scaffolded App
|
|
13
|
-
|
|
14
|
-
After scaffolding, your app has these key areas to extend:
|
|
15
|
-
|
|
16
|
-
| Area | Location | Purpose |
|
|
17
|
-
|------|----------|---------|
|
|
18
|
-
| Webhook handling | `app/server/src/functions/seekaAppWebhook.ts` | Process Seeka events |
|
|
19
|
-
| Business logic | `app/server/src/app/services/` | External API integrations |
|
|
20
|
-
| Data models | `app/lib/src/models/` | Shared TypeScript interfaces |
|
|
21
|
-
| Settings validation | `app/lib/src/validation/` | Validate installation settings |
|
|
22
|
-
| Background jobs | `app/server/src/app/jobs/` | Async processing |
|
|
23
|
-
|
|
24
|
-
## Step 1: Define Your Data Models
|
|
25
|
-
|
|
26
|
-
Start by defining the data structures your app will use.
|
|
27
|
-
|
|
28
|
-
### Installation Settings
|
|
29
|
-
|
|
30
|
-
Edit `app/lib/src/models/index.ts` to define settings users will configure:
|
|
31
|
-
|
|
32
|
-
```typescript
|
|
33
|
-
export interface YourAppInstallationSettings {
|
|
34
|
-
// Required settings
|
|
35
|
-
apiKey: string;
|
|
36
|
-
accountId: string;
|
|
37
|
-
|
|
38
|
-
// Optional settings
|
|
39
|
-
enableFeatureX?: boolean;
|
|
40
|
-
customMapping?: Record<string, string>;
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### Installation Context
|
|
45
|
-
|
|
46
|
-
The installation context stores the full state:
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
export interface YourAppInstallContext {
|
|
50
|
-
applicationInstallId: string;
|
|
51
|
-
organisationId: string;
|
|
52
|
-
organisationBrandId: string;
|
|
53
|
-
installedAt: string;
|
|
54
|
-
installationState?: {
|
|
55
|
-
grantedPermissions: string[];
|
|
56
|
-
installationSettings: YourAppInstallationSettings;
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Step 2: Add Settings Validation
|
|
62
|
-
|
|
63
|
-
Edit `app/lib/src/validation/index.ts` to validate settings on installation:
|
|
64
|
-
|
|
65
|
-
```typescript
|
|
66
|
-
import { Logger } from 'winston';
|
|
67
|
-
import { YourAppInstallationSettings } from '../models';
|
|
68
|
-
|
|
69
|
-
export const validateInstallationSettings = async (
|
|
70
|
-
settings: YourAppInstallationSettings,
|
|
71
|
-
logger: Logger
|
|
72
|
-
): Promise<string | null> => {
|
|
73
|
-
// Return error message string if invalid, null if valid
|
|
74
|
-
|
|
75
|
-
if (!settings.apiKey) {
|
|
76
|
-
return 'API Key is required';
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (!settings.accountId) {
|
|
80
|
-
return 'Account ID is required';
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Optionally validate API key works
|
|
84
|
-
try {
|
|
85
|
-
const isValid = await testApiConnection(settings.apiKey, settings.accountId);
|
|
86
|
-
if (!isValid) {
|
|
87
|
-
return 'Invalid API credentials';
|
|
88
|
-
}
|
|
89
|
-
} catch (error) {
|
|
90
|
-
logger.error('Failed to validate API credentials', { error });
|
|
91
|
-
return 'Failed to validate API credentials';
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return null; // Valid
|
|
95
|
-
};
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## Step 3: Create Your Service Layer
|
|
99
|
-
|
|
100
|
-
Add services in `app/server/src/app/services/` for external integrations:
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
// app/server/src/app/services/externalPlatform.ts
|
|
104
|
-
import { Logger } from 'winston';
|
|
105
|
-
|
|
106
|
-
export interface ExternalPlatformConfig {
|
|
107
|
-
apiKey: string;
|
|
108
|
-
accountId: string;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export class ExternalPlatformService {
|
|
112
|
-
private config: ExternalPlatformConfig;
|
|
113
|
-
private logger: Logger;
|
|
114
|
-
|
|
115
|
-
constructor(config: ExternalPlatformConfig, logger: Logger) {
|
|
116
|
-
this.config = config;
|
|
117
|
-
this.logger = logger;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async sendEvent(eventData: any): Promise<boolean> {
|
|
121
|
-
this.logger.debug('Sending event to external platform', { eventData });
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
const response = await fetch('https://api.external-platform.com/events', {
|
|
125
|
-
method: 'POST',
|
|
126
|
-
headers: {
|
|
127
|
-
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
128
|
-
'Content-Type': 'application/json'
|
|
129
|
-
},
|
|
130
|
-
body: JSON.stringify({
|
|
131
|
-
account_id: this.config.accountId,
|
|
132
|
-
...eventData
|
|
133
|
-
})
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
if (!response.ok) {
|
|
137
|
-
this.logger.error('External API error', {
|
|
138
|
-
status: response.status,
|
|
139
|
-
body: await response.text()
|
|
140
|
-
});
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return true;
|
|
145
|
-
} catch (error) {
|
|
146
|
-
this.logger.error('Failed to send event', { error });
|
|
147
|
-
throw error;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
## Step 4: Handle Activity Events
|
|
154
|
-
|
|
155
|
-
The main place to add your logic is in the activity handler. Edit `app/server/src/app/services/activities.ts`:
|
|
156
|
-
|
|
157
|
-
```typescript
|
|
158
|
-
import { Logger } from 'winston';
|
|
159
|
-
import { SeekaActivityAcceptedWebhookPayload } from '@seeka-labs/sdk-apps-server';
|
|
160
|
-
import { YourAppInstallContext } from '@your-org/your-app-lib';
|
|
161
|
-
import { ExternalPlatformService } from './externalPlatform';
|
|
162
|
-
|
|
163
|
-
export const processActivity = async (
|
|
164
|
-
activity: SeekaActivityAcceptedWebhookPayload['content'],
|
|
165
|
-
installation: YourAppInstallContext,
|
|
166
|
-
logger: Logger
|
|
167
|
-
): Promise<void> => {
|
|
168
|
-
const settings = installation.installationState?.installationSettings;
|
|
169
|
-
if (!settings) {
|
|
170
|
-
logger.warn('No installation settings found');
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Initialize your service
|
|
175
|
-
const service = new ExternalPlatformService({
|
|
176
|
-
apiKey: settings.apiKey,
|
|
177
|
-
accountId: settings.accountId
|
|
178
|
-
}, logger);
|
|
179
|
-
|
|
180
|
-
// Transform Seeka activity to external format
|
|
181
|
-
const eventData = {
|
|
182
|
-
event_name: activity.activity.activityName,
|
|
183
|
-
event_id: activity.activity.activityId,
|
|
184
|
-
timestamp: activity.activity.timestamp,
|
|
185
|
-
user_data: {
|
|
186
|
-
email: activity.person?.email,
|
|
187
|
-
phone: activity.person?.phone
|
|
188
|
-
},
|
|
189
|
-
custom_data: activity.activity.properties
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
// Send to external platform
|
|
193
|
-
await service.sendEvent(eventData);
|
|
194
|
-
|
|
195
|
-
logger.info('Activity processed successfully', {
|
|
196
|
-
activityId: activity.activity.activityId
|
|
197
|
-
});
|
|
198
|
-
};
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
## Step 5: Wire Up the Queue Handler
|
|
202
|
-
|
|
203
|
-
Edit `app/server/src/functions/trackActivityQueueHandler.ts` to use your service:
|
|
204
|
-
|
|
205
|
-
```typescript
|
|
206
|
-
import { app, InvocationContext } from '@azure/functions';
|
|
207
|
-
import { tryGetInstallation, startServices, childLogger } from '@seeka-labs/sdk-apps-server-host';
|
|
208
|
-
import { TrackActivityQueueItem } from '../app/models';
|
|
209
|
-
import { processActivity } from '../app/services/activities';
|
|
210
|
-
import { queueNames } from '../app/jobs';
|
|
211
|
-
|
|
212
|
-
app.storageQueue('trackActivityQueueHandler', {
|
|
213
|
-
queueName: queueNames.trackActivity,
|
|
214
|
-
connection: 'AzureWebJobsStorage',
|
|
215
|
-
handler: async (item: TrackActivityQueueItem, context: InvocationContext) => {
|
|
216
|
-
let logger = childLogger({}, null, null, context);
|
|
217
|
-
|
|
218
|
-
await startServices(logger);
|
|
219
|
-
|
|
220
|
-
const installation = await tryGetInstallation(
|
|
221
|
-
item.applicationInstallId,
|
|
222
|
-
true,
|
|
223
|
-
logger
|
|
224
|
-
);
|
|
225
|
-
|
|
226
|
-
if (!installation) {
|
|
227
|
-
logger.error('Installation not found', {
|
|
228
|
-
applicationInstallId: item.applicationInstallId
|
|
229
|
-
});
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
logger = childLogger({}, installation, logger, context);
|
|
234
|
-
|
|
235
|
-
await processActivity(item.payload, installation, logger);
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
## Step 6: Local Development
|
|
241
|
-
|
|
242
|
-
### Set Up Environment
|
|
243
|
-
|
|
244
|
-
1. Copy the template settings:
|
|
245
|
-
```bash
|
|
246
|
-
cp app/server/local.settings.template.json app/server/local.settings.json
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
2. Fill in your environment variables in `local.settings.json`
|
|
250
|
-
|
|
251
|
-
### Run Locally
|
|
252
|
-
|
|
253
|
-
```bash
|
|
254
|
-
# Install dependencies
|
|
255
|
-
yarn install
|
|
256
|
-
|
|
257
|
-
# Build all packages
|
|
258
|
-
yarn build
|
|
259
|
-
|
|
260
|
-
# Start the function app
|
|
261
|
-
cd app/server
|
|
262
|
-
yarn dev
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
### Test with ngrok
|
|
266
|
-
|
|
267
|
-
```bash
|
|
268
|
-
# Expose local server
|
|
269
|
-
ngrok http 7071
|
|
270
|
-
|
|
271
|
-
# Use the ngrok URL in Seeka app configuration
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
## Step 7: Add Tests
|
|
275
|
-
|
|
276
|
-
Create tests in `app/server/src/app/services/__tests__/`:
|
|
277
|
-
|
|
278
|
-
```typescript
|
|
279
|
-
// externalPlatform.test.ts
|
|
280
|
-
import { ExternalPlatformService } from '../externalPlatform';
|
|
281
|
-
|
|
282
|
-
describe('ExternalPlatformService', () => {
|
|
283
|
-
it('should send event successfully', async () => {
|
|
284
|
-
// Mock fetch
|
|
285
|
-
global.fetch = jest.fn().mockResolvedValue({
|
|
286
|
-
ok: true,
|
|
287
|
-
json: () => Promise.resolve({ success: true })
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
const service = new ExternalPlatformService({
|
|
291
|
-
apiKey: 'test-key',
|
|
292
|
-
accountId: 'test-account'
|
|
293
|
-
}, mockLogger);
|
|
294
|
-
|
|
295
|
-
const result = await service.sendEvent({ test: 'data' });
|
|
296
|
-
|
|
297
|
-
expect(result).toBe(true);
|
|
298
|
-
expect(fetch).toHaveBeenCalledWith(
|
|
299
|
-
'https://api.external-platform.com/events',
|
|
300
|
-
expect.objectContaining({
|
|
301
|
-
method: 'POST'
|
|
302
|
-
})
|
|
303
|
-
);
|
|
304
|
-
});
|
|
305
|
-
});
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
## Common Extension Patterns
|
|
309
|
-
|
|
310
|
-
### Adding a New Webhook Type Handler
|
|
311
|
-
|
|
312
|
-
In `seekaAppWebhook.ts`, add a case to the switch statement:
|
|
313
|
-
|
|
314
|
-
```typescript
|
|
315
|
-
case SeekaWebhookCallType.YourNewType: {
|
|
316
|
-
const payload = body as YourNewTypePayload;
|
|
317
|
-
await handleYourNewType(payload, installation, logger);
|
|
318
|
-
break;
|
|
319
|
-
}
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
### Adding a New API Endpoint
|
|
323
|
-
|
|
324
|
-
Create a new route in `app/server/src/app/api/routes/`:
|
|
325
|
-
|
|
326
|
-
```typescript
|
|
327
|
-
// yourNewEndpoint.ts
|
|
328
|
-
import { HttpRequest, HttpResponseInit } from '@azure/functions';
|
|
329
|
-
import { Logger } from 'winston';
|
|
330
|
-
|
|
331
|
-
export const yourNewEndpoint = async (
|
|
332
|
-
req: HttpRequest,
|
|
333
|
-
logger: Logger
|
|
334
|
-
): Promise<HttpResponseInit> => {
|
|
335
|
-
// Your logic here
|
|
336
|
-
return {
|
|
337
|
-
status: 200,
|
|
338
|
-
jsonBody: { success: true }
|
|
339
|
-
};
|
|
340
|
-
};
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
Then register it in `router.ts`.
|
|
344
|
-
|
|
345
|
-
## Next Steps
|
|
346
|
-
|
|
347
|
-
- See `common-patterns.md` for more implementation patterns
|
|
348
|
-
- See `data-flow.md` for understanding data flow
|
|
349
|
-
- See `../examples/` for complete example implementations
|