@elevasis/sdk 0.7.11 → 0.7.12

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.
@@ -0,0 +1,494 @@
1
+ ---
2
+ title: Platform Adapters
3
+ description: Type-safe singleton adapters for built-in platform services -- scheduler, storage, LLM, PDF, approval, notifications, acqDb, execution, and email -- no credentials required
4
+ loadWhen: "Using platform service adapters (scheduler, storage, llm, pdf, approval, acqDb, notifications, execution, email)"
5
+ ---
6
+
7
+ Platform adapters are singleton objects imported directly from `@elevasis/sdk/worker`. They require no credential argument because the platform injects context server-side. For integration adapters (Attio, Stripe, etc.), see [Integration Adapters](adapters-integration.mdx).
8
+
9
+ ```typescript
10
+ import {
11
+ acqDb, scheduler, storage, pdf, approval,
12
+ notifications, llm, execution, email,
13
+ } from '@elevasis/sdk/worker'
14
+ ```
15
+
16
+ ---
17
+
18
+ ## Quick Reference
19
+
20
+ | Import | Methods | Purpose |
21
+ | --------------- | ------- | ------------------------------------ |
22
+ | `acqDb` | 35 | Acquisition database CRUD and sync |
23
+ | `scheduler` | 9 | Task schedule management |
24
+ | `storage` | 5 | File upload, download, signed URLs |
25
+ | `pdf` | 2 | PDF rendering to storage or buffer |
26
+ | `approval` | 2 | Human-in-the-loop approval gates |
27
+ | `notifications` | 1 | In-app team notifications |
28
+ | `llm` | 1 | LLM inference with structured output |
29
+ | `execution` | 1 | Trigger nested child executions |
30
+ | `email` | 1 | Send email to org members |
31
+
32
+ ---
33
+
34
+ ## Scheduler Adapter
35
+
36
+ Singleton -- 9 methods for task schedule management.
37
+
38
+ ```typescript
39
+ import { scheduler } from '@elevasis/sdk/worker'
40
+ ```
41
+
42
+ ### Methods
43
+
44
+ | Method | Params | Returns |
45
+ | -------------------------------- | ------------------------------ | ---------------------- |
46
+ | `createSchedule` | `CreateScheduleInput` | `TaskSchedule` |
47
+ | `updateAnchor` | `{ scheduleId, anchorAt }` | `TaskSchedule` |
48
+ | `deleteSchedule` | `{ scheduleId }` | `void` |
49
+ | `findByIdempotencyKey` | `{ idempotencyKey }` | `TaskSchedule | null` |
50
+ | `deleteScheduleByIdempotencyKey` | `{ idempotencyKey }` | `void` |
51
+ | `listSchedules` | `{ status?, limit?, offset? }` | `TaskSchedule[]` |
52
+ | `getSchedule` | `{ scheduleId }` | `TaskSchedule` |
53
+ | `cancelSchedule` | `{ scheduleId }` | `void` |
54
+ | `cancelSchedulesByMetadata` | `{ metadata }` | `{ cancelledCount }` |
55
+
56
+ ### Examples
57
+
58
+ ```typescript
59
+ // Create a relative schedule (follow-up sequence)
60
+ const schedule = await scheduler.createSchedule({
61
+ organizationId: context.organizationId,
62
+ name: 'Proposal follow-up',
63
+ target: { resourceType: 'workflow', resourceId: 'send-followup' },
64
+ scheduleConfig: {
65
+ type: 'relative',
66
+ anchorAt: '2026-03-15T10:00:00Z',
67
+ anchorLabel: 'proposal_sent_date',
68
+ items: [
69
+ { offset: '+3d', payload: { step: 'first-followup' }, label: 'First follow-up' },
70
+ { offset: '+7d', payload: { step: 'second-followup' }, label: 'Second follow-up' },
71
+ ],
72
+ },
73
+ metadata: { dealId: 'deal-123', contactEmail: 'jane@acme.com' },
74
+ idempotencyKey: 'proposal-followup-deal-123',
75
+ })
76
+
77
+ // Reschedule (update anchor)
78
+ await scheduler.updateAnchor({
79
+ scheduleId: schedule.id,
80
+ anchorAt: '2026-03-20T10:00:00Z',
81
+ })
82
+
83
+ // Cancel all schedules matching metadata
84
+ await scheduler.cancelSchedulesByMetadata({
85
+ metadata: { dealId: 'deal-123' },
86
+ })
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Storage Adapter
92
+
93
+ Singleton -- 5 methods for file storage operations. All paths are relative to the organization's storage prefix (injected server-side).
94
+
95
+ ```typescript
96
+ import { storage } from '@elevasis/sdk/worker'
97
+ ```
98
+
99
+ ### Methods
100
+
101
+ | Method | Params | Returns |
102
+ | ----------------- | ----------------------- | ------------------------ |
103
+ | `upload` | `StorageUploadInput` | `StorageUploadOutput` |
104
+ | `download` | `StorageDownloadInput` | `StorageDownloadOutput` |
105
+ | `createSignedUrl` | `StorageSignedUrlInput` | `StorageSignedUrlOutput` |
106
+ | `delete` | `StorageDeleteInput` | `StorageDeleteOutput` |
107
+ | `list` | `StorageListInput` | `StorageListOutput` |
108
+
109
+ ### Examples
110
+
111
+ ```typescript
112
+ // Upload a PDF
113
+ await storage.upload({
114
+ bucket: 'acquisition',
115
+ path: 'proposals/deal-123/proposal.pdf',
116
+ content: base64PdfContent,
117
+ contentType: 'application/pdf',
118
+ })
119
+
120
+ // Generate a signed URL (temporary access)
121
+ const { signedUrl } = await storage.createSignedUrl({
122
+ bucket: 'acquisition',
123
+ path: 'proposals/deal-123/proposal.pdf',
124
+ })
125
+
126
+ // List files under a prefix
127
+ const files = await storage.list({
128
+ bucket: 'acquisition',
129
+ path: 'proposals/deal-123/',
130
+ })
131
+ ```
132
+
133
+ ---
134
+
135
+ ## LLM Adapter
136
+
137
+ Singleton -- 1 method with a generic `<T>` for typed structured output. No API keys needed -- keys are resolved server-side from environment variables.
138
+
139
+ ```typescript
140
+ import { llm } from '@elevasis/sdk/worker'
141
+ ```
142
+
143
+ ### Method
144
+
145
+ | Method | Params | Returns |
146
+ | --------------- | -------------------------------------- | -------------------------- |
147
+ | `generate<T>` | `Omit<LLMGenerateRequest, 'signal'>` | `LLMGenerateResponse<T>` |
148
+
149
+ The `signal` property (AbortSignal) is not serializable over the postMessage boundary. Abort is handled at the worker level.
150
+
151
+ ### Example
152
+
153
+ ```typescript
154
+ interface Classification {
155
+ category: 'interested' | 'not-interested' | 'bounced'
156
+ confidence: number
157
+ summary: string
158
+ }
159
+
160
+ const response = await llm.generate<Classification>({
161
+ provider: 'anthropic',
162
+ model: 'claude-sonnet-4-5',
163
+ messages: [
164
+ { role: 'system', content: 'Classify this email reply.' },
165
+ { role: 'user', content: emailText },
166
+ ],
167
+ responseSchema: {
168
+ type: 'object',
169
+ properties: {
170
+ category: { type: 'string', enum: ['interested', 'not-interested', 'bounced'] },
171
+ confidence: { type: 'number', minimum: 0, maximum: 1 },
172
+ summary: { type: 'string' },
173
+ },
174
+ required: ['category', 'confidence', 'summary'],
175
+ },
176
+ temperature: 0.1,
177
+ })
178
+
179
+ // response.output is typed as Classification
180
+ const { category, confidence, summary } = response.output
181
+ ```
182
+
183
+ **Supported models:** See the full model table in [Platform Tools](index.mdx#llm-tool).
184
+
185
+ ---
186
+
187
+ ## PDF Adapter
188
+
189
+ Singleton -- 2 methods for rendering PDFDocument structures to files or buffers. No credential required.
190
+
191
+ ```typescript
192
+ import { pdf } from '@elevasis/sdk/worker'
193
+ ```
194
+
195
+ ### Methods
196
+
197
+ | Method | Params | Returns |
198
+ | ---------------- | ------------------------------------------------- | --------------------------- |
199
+ | `render` | `{ document, theme?, storage: { bucket, path } }` | `{ success, pdfUrl, size }` |
200
+ | `renderToBuffer` | `{ document, theme? }` | `{ buffer }` |
201
+
202
+ ### Example
203
+
204
+ ```typescript
205
+ // Render to storage (returns a URL)
206
+ const result = await pdf.render({
207
+ document: proposalDocument,
208
+ storage: { bucket: 'acquisition', path: 'proposals/deal-123/proposal.pdf' },
209
+ })
210
+ console.log(result.pdfUrl)
211
+
212
+ // Render to buffer (for inline processing)
213
+ const { buffer } = await pdf.renderToBuffer({ document: proposalDocument })
214
+ ```
215
+
216
+ ---
217
+
218
+ ## Approval Adapter
219
+
220
+ Singleton -- 2 methods for creating and managing human-in-the-loop (HITL) approval tasks. No credential required.
221
+
222
+ ```typescript
223
+ import { approval } from '@elevasis/sdk/worker'
224
+ ```
225
+
226
+ ### Methods
227
+
228
+ | Method | Params | Returns |
229
+ | ------------------ | ---------------------------------------------------------------------------------------- | ------------- |
230
+ | `create` | `{ actions, context, description?, priority?, humanCheckpoint?, metadata?, expiresAt? }` | `{ id }` |
231
+ | `deleteByMetadata` | `{ metadata, status? }` | `{ deleted }` |
232
+
233
+ ### Example
234
+
235
+ ```typescript
236
+ // Create an approval gate
237
+ const task = await approval.create({
238
+ actions: [
239
+ { id: 'approve', label: 'Approve', type: 'primary' },
240
+ { id: 'reject', label: 'Reject', type: 'danger' },
241
+ ],
242
+ context: { dealId: 'deal-123', proposalUrl: 'https://...' },
243
+ description: 'Review proposal for Acme Corp',
244
+ humanCheckpoint: 'proposal-review',
245
+ metadata: { dealId: 'deal-123' },
246
+ })
247
+
248
+ // Clean up stale tasks
249
+ await approval.deleteByMetadata({
250
+ metadata: { dealId: 'deal-123' },
251
+ status: 'pending',
252
+ })
253
+ ```
254
+
255
+ ---
256
+
257
+ ## Notifications Adapter
258
+
259
+ Singleton -- 1 method for sending in-app team notifications. `userId` and `organizationId` are injected server-side.
260
+
261
+ ```typescript
262
+ import { notifications } from '@elevasis/sdk/worker'
263
+ ```
264
+
265
+ ### Method
266
+
267
+ | Method | Params | Returns |
268
+ | -------- | ---------------------- | ------- |
269
+ | `create` | `NotificationSDKInput` | `void` |
270
+
271
+ `NotificationSDKInput` fields: `category`, `title`, `message`, `actionUrl?`, `metadata?`
272
+
273
+ ### Example
274
+
275
+ ```typescript
276
+ await notifications.create({
277
+ category: 'acquisition',
278
+ title: 'New lead qualified',
279
+ message: 'Acme Corp has been qualified and moved to proposal stage.',
280
+ actionUrl: '/deals/deal-123',
281
+ })
282
+ ```
283
+
284
+ ---
285
+
286
+ ## AcqDb Adapter
287
+
288
+ Singleton -- 35 methods for acquisition database management (lists, companies, contacts, deals, deal-sync). `organizationId` is injected server-side -- never pass it.
289
+
290
+ ```typescript
291
+ import { acqDb } from '@elevasis/sdk/worker'
292
+ ```
293
+
294
+ ### Methods
295
+
296
+ **List operations:**
297
+
298
+ | Method | Params | Returns |
299
+ | ------------ | -------------------------------------------- | ----------- |
300
+ | `listLists` | none | `AcqList[]` |
301
+ | `createList` | `Omit<CreateListParams, 'organizationId'>` | `AcqList` |
302
+ | `updateList` | `{ id } & UpdateListParams` | `AcqList` |
303
+ | `deleteList` | `{ id }` | `void` |
304
+
305
+ **Company operations:**
306
+
307
+ | Method | Params | Returns |
308
+ | --------------- | ----------------------------------------------- | -------------------- |
309
+ | `createCompany` | `Omit<CreateCompanyParams, 'organizationId'>` | `AcqCompany` |
310
+ | `upsertCompany` | `Omit<UpsertCompanyParams, 'organizationId'>` | `AcqCompany` |
311
+ | `updateCompany` | `{ id } & UpdateCompanyParams` | `AcqCompany` |
312
+ | `getCompany` | `{ id }` | `AcqCompany | null` |
313
+ | `listCompanies` | `{ filters? }` | `AcqCompany[]` |
314
+ | `deleteCompany` | `{ id }` | `void` |
315
+
316
+ **Contact operations:**
317
+
318
+ | Method | Params | Returns |
319
+ | -------------------- | ----------------------------------------------- | ------------------------------- |
320
+ | `createContact` | `Omit<CreateContactParams, 'organizationId'>` | `AcqContact` |
321
+ | `upsertContact` | `Omit<UpsertContactParams, 'organizationId'>` | `AcqContact` |
322
+ | `updateContact` | `{ id } & UpdateContactParams` | `AcqContact` |
323
+ | `getContact` | `{ id }` | `AcqContact | null` |
324
+ | `getContactByEmail` | `{ email }` | `AcqContact | null` |
325
+ | `listContacts` | `{ filters?, pagination? }` | `PaginatedResult<AcqContact>` |
326
+ | `deleteContact` | `{ id }` | `void` |
327
+ | `bulkImportContacts` | `Omit<BulkImportParams, 'organizationId'>` | `BulkImportResult` |
328
+
329
+ **Deal operations:**
330
+
331
+ | Method | Params | Returns |
332
+ | ---------------------- | -------------------------------------------- | ----------------- |
333
+ | `upsertDeal` | `Omit<UpsertDealParams, 'organizationId'>` | `AcqDeal` |
334
+ | `getDealByEmail` | `{ email }` | `AcqDeal | null` |
335
+ | `getDealByEnvelopeId` | `{ envelopeId }` | `AcqDeal | null` |
336
+ | `updateDealEnvelopeId` | `{ attioDealId, envelopeId }` | `AcqDeal | null` |
337
+ | `getDealByAttioId` | `{ attioDealId }` | `AcqDeal | null` |
338
+
339
+ **Deal-sync operations:**
340
+
341
+ | Method | Params | Returns |
342
+ | ------------------------------- | ------------------------------------------------------- | ------------------------------------- |
343
+ | `updateDiscoveryData` | `Omit<UpdateDiscoveryDataParams, 'organizationId'>` | `void` |
344
+ | `updateProposalData` | `Omit<UpdateProposalDataParams, 'organizationId'>` | `void` |
345
+ | `markProposalSent` | `Omit<MarkProposalSentParams, 'organizationId'>` | `void` |
346
+ | `markProposalReviewed` | `Omit<MarkProposalReviewedParams, 'organizationId'>` | `void` |
347
+ | `updateCloseLostReason` | `Omit<UpdateCloseLostReasonParams, 'organizationId'>` | `void` |
348
+ | `updateFees` | `Omit<UpdateFeesParams, 'organizationId'>` | `void` |
349
+ | `syncDealStage` | `Omit<SyncDealStageParams, 'organizationId'>` | `void` |
350
+ | `setContactNurture` | `Omit<SetContactNurtureParams, 'organizationId'>` | `void` |
351
+ | `cancelSchedulesAndHitlByEmail` | `Omit<..., 'organizationId'>` | `{ schedulesCancelled, hitlDeleted }` |
352
+ | `cancelHitlByDealId` | `Omit<..., 'organizationId'>` | `{ hitlDeleted }` |
353
+ | `clearDealFields` | `Omit<ClearDealFieldsParams, 'organizationId'>` | `void` |
354
+ | `deleteDeal` | `Omit<DeleteDealParams, 'organizationId'>` | `void` |
355
+
356
+ ### Example
357
+
358
+ ```typescript
359
+ const deal = await acqDb.getDealByEmail({ email: 'jane@acme.com' })
360
+ if (!deal) {
361
+ await acqDb.upsertDeal({
362
+ attioDealId: 'deal-123',
363
+ contactEmail: 'jane@acme.com',
364
+ })
365
+ }
366
+
367
+ // Bulk import contacts
368
+ await acqDb.bulkImportContacts({
369
+ listId: 'list-abc',
370
+ contacts: [
371
+ { email: 'a@example.com', firstName: 'Alice' },
372
+ { email: 'b@example.com', firstName: 'Bob' },
373
+ ],
374
+ })
375
+ ```
376
+
377
+ ---
378
+
379
+ ## Execution Adapter
380
+
381
+ Singleton -- 1 method for triggering another resource (workflow or agent) as a nested child execution. Maximum depth: 5 levels.
382
+
383
+ ```typescript
384
+ import { execution } from '@elevasis/sdk/worker'
385
+ ```
386
+
387
+ ### Method
388
+
389
+ | Method | Params | Returns |
390
+ | --------- | ------------------------ | ------------------------------------------ |
391
+ | `trigger` | `{ resourceId, input? }` | `{ success, executionId, output, error? }` |
392
+
393
+ ### Example
394
+
395
+ ```typescript
396
+ const result = await execution.trigger({
397
+ resourceId: 'send-welcome-sequence',
398
+ input: { userId: newUser.id, email: newUser.email },
399
+ })
400
+
401
+ if (!result.success) {
402
+ throw new Error(`Child workflow failed: ${result.error}`)
403
+ }
404
+ ```
405
+
406
+ ---
407
+
408
+ ## Email Adapter
409
+
410
+ Singleton -- 1 method for sending platform emails to organization members (from `notifications@elevasis.io`). For client-facing emails, use the Resend or Instantly integration adapters instead.
411
+
412
+ ```typescript
413
+ import { email } from '@elevasis/sdk/worker'
414
+ ```
415
+
416
+ ### Method
417
+
418
+ | Method | Params | Returns |
419
+ | ------ | ------------------------------------------------------------------------------- | --------------------------- |
420
+ | `send` | `{ subject, html?, text?, userIds?, targetRole?, targetAll?, replyTo?, tags? }` | `{ sent, failed, errors? }` |
421
+
422
+ ### Example
423
+
424
+ ```typescript
425
+ // Notify all org members
426
+ await email.send({
427
+ subject: 'New deal closed',
428
+ text: 'Acme Corp has signed the contract.',
429
+ targetAll: true,
430
+ })
431
+
432
+ // Notify specific users
433
+ await email.send({
434
+ subject: 'Action required',
435
+ html: '\<p\>Please review the proposal.\</p\>',
436
+ userIds: ['user-abc', 'user-def'],
437
+ })
438
+ ```
439
+
440
+ ---
441
+
442
+ ## Custom Adapters with `createAdapter`
443
+
444
+ The generic `createAdapter` factory is exported for building adapters for any tool not already covered. Define a type map and call the factory.
445
+
446
+ ```typescript
447
+ import { createAdapter } from '@elevasis/sdk/worker'
448
+
449
+ // 1. Define a type map
450
+ type MyToolMap = {
451
+ doSomething: { params: { input: string }; result: { output: string } }
452
+ listItems: { params: { limit?: number }; result: { items: string[] } }
453
+ getStatus: { params: Record<string, never>; result: { healthy: boolean } }
454
+ }
455
+
456
+ // 2. Create the adapter
457
+ const myTool = createAdapter<MyToolMap>('my-tool', [
458
+ 'doSomething', 'listItems', 'getStatus',
459
+ ], 'my-credential') // credential is optional
460
+
461
+ // 3. Use it (fully typed)
462
+ const result = await myTool.doSomething({ input: 'hello' })
463
+ // ^-- { output: string }
464
+ ```
465
+
466
+ Method names are compile-time checked against the type map keys.
467
+
468
+ ---
469
+
470
+ ## Error Handling
471
+
472
+ All adapter calls throw `PlatformToolError` on failure, with a `code` field and `retryable` flag:
473
+
474
+ ```typescript
475
+ import { PlatformToolError } from '@elevasis/sdk/worker'
476
+
477
+ try {
478
+ await scheduler.listSchedules({ status: 'active' })
479
+ } catch (err) {
480
+ if (err instanceof PlatformToolError) {
481
+ console.log(err.message) // Human-readable error
482
+ console.log(err.code) // e.g., 'rate_limit_exceeded', 'service_unavailable'
483
+ console.log(err.retryable) // true for transient errors
484
+ }
485
+ }
486
+ ```
487
+
488
+ Retryable error codes: `rate_limit_exceeded`, `network_error`, `timeout_error`, `api_error`, `service_unavailable`, `server_unavailable`.
489
+
490
+ **Timeouts:** LLM calls have a 120s timeout. All other tool calls have a 60s timeout.
491
+
492
+ ---
493
+
494
+ **Last Updated:** 2026-03-05