runwork 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.
Files changed (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +134 -0
  3. package/bin/runwork.js +2 -0
  4. package/bundled-types/agents.d.ts +3 -0
  5. package/bundled-types/ai.d.ts +2 -0
  6. package/bundled-types/app-registry.d.ts +74 -0
  7. package/bundled-types/channels.d.ts +2 -0
  8. package/bundled-types/components.d.ts +1 -0
  9. package/bundled-types/core-agent.d.ts +265 -0
  10. package/bundled-types/core-ai.d.ts +170 -0
  11. package/bundled-types/core-base-agent.d.ts +89 -0
  12. package/bundled-types/core-channels.d.ts +42 -0
  13. package/bundled-types/core-components.d.ts +21 -0
  14. package/bundled-types/core-endpoints.d.ts +198 -0
  15. package/bundled-types/core-entities.d.ts +276 -0
  16. package/bundled-types/core-entity-do.d.ts +119 -0
  17. package/bundled-types/core-events.d.ts +52 -0
  18. package/bundled-types/core-file-storage.d.ts +216 -0
  19. package/bundled-types/core-integration-entities.d.ts +147 -0
  20. package/bundled-types/core-integrations.d.ts +143 -0
  21. package/bundled-types/core-routes.d.ts +33 -0
  22. package/bundled-types/core-scheduler.d.ts +180 -0
  23. package/bundled-types/core-utils.d.ts +85 -0
  24. package/bundled-types/core-workflow-cloudflare.d.ts +85 -0
  25. package/bundled-types/core-workflow-config.d.ts +18 -0
  26. package/bundled-types/core-workflow-coordinator.d.ts +78 -0
  27. package/bundled-types/core-workflow-instance.d.ts +82 -0
  28. package/bundled-types/core-workflow-types.d.ts +251 -0
  29. package/bundled-types/core-workflows.d.ts +75 -0
  30. package/bundled-types/core-workspace.d.ts +454 -0
  31. package/bundled-types/create-app.d.ts +57 -0
  32. package/bundled-types/endpoints.d.ts +2 -0
  33. package/bundled-types/entities.d.ts +5 -0
  34. package/bundled-types/events.d.ts +2 -0
  35. package/bundled-types/index.d.ts +19 -0
  36. package/bundled-types/integrations.d.ts +2 -0
  37. package/bundled-types/routes.d.ts +2 -0
  38. package/bundled-types/scheduler.d.ts +2 -0
  39. package/bundled-types/storage.d.ts +2 -0
  40. package/bundled-types/test-entry.d.ts +21 -0
  41. package/bundled-types/types.d.ts +1 -0
  42. package/bundled-types/vite.d.ts +23 -0
  43. package/bundled-types/workflows.d.ts +14 -0
  44. package/bundled-types/workspace.d.ts +2 -0
  45. package/dist/__tests__/types-manager.test.d.ts +1 -0
  46. package/dist/__tests__/types-manager.test.js +85 -0
  47. package/dist/api/__tests__/client.test.d.ts +1 -0
  48. package/dist/api/__tests__/client.test.js +264 -0
  49. package/dist/api/client.d.ts +72 -0
  50. package/dist/api/client.js +144 -0
  51. package/dist/auth/__tests__/store.test.d.ts +1 -0
  52. package/dist/auth/__tests__/store.test.js +103 -0
  53. package/dist/auth/browser.d.ts +2 -0
  54. package/dist/auth/browser.js +7 -0
  55. package/dist/auth/store.d.ts +5 -0
  56. package/dist/auth/store.js +33 -0
  57. package/dist/commands/clone.d.ts +2 -0
  58. package/dist/commands/clone.js +90 -0
  59. package/dist/commands/deploy.d.ts +2 -0
  60. package/dist/commands/deploy.js +43 -0
  61. package/dist/commands/dev.d.ts +2 -0
  62. package/dist/commands/dev.js +188 -0
  63. package/dist/commands/init.d.ts +2 -0
  64. package/dist/commands/init.js +87 -0
  65. package/dist/commands/login.d.ts +2 -0
  66. package/dist/commands/login.js +32 -0
  67. package/dist/commands/logout.d.ts +2 -0
  68. package/dist/commands/logout.js +13 -0
  69. package/dist/commands/logs.d.ts +2 -0
  70. package/dist/commands/logs.js +166 -0
  71. package/dist/generated/bundled-types.d.ts +1 -0
  72. package/dist/generated/bundled-types.js +44 -0
  73. package/dist/generated/version.d.ts +1 -0
  74. package/dist/generated/version.js +2 -0
  75. package/dist/git/__tests__/credentials.test.d.ts +1 -0
  76. package/dist/git/__tests__/credentials.test.js +128 -0
  77. package/dist/git/auto-commit.d.ts +3 -0
  78. package/dist/git/auto-commit.js +209 -0
  79. package/dist/git/credentials.d.ts +15 -0
  80. package/dist/git/credentials.js +65 -0
  81. package/dist/index.d.ts +1 -0
  82. package/dist/index.js +31 -0
  83. package/dist/logs/tailer.d.ts +13 -0
  84. package/dist/logs/tailer.js +135 -0
  85. package/dist/template/manifest.d.ts +17 -0
  86. package/dist/template/manifest.js +102 -0
  87. package/dist/types-manager.d.ts +1 -0
  88. package/dist/types-manager.js +35 -0
  89. package/dist/types.d.ts +27 -0
  90. package/dist/types.js +1 -0
  91. package/dist/utils/__tests__/prompt.test.d.ts +1 -0
  92. package/dist/utils/__tests__/prompt.test.js +103 -0
  93. package/dist/utils/fs.d.ts +5 -0
  94. package/dist/utils/fs.js +23 -0
  95. package/dist/utils/prompt.d.ts +4 -0
  96. package/dist/utils/prompt.js +34 -0
  97. package/dist/utils/zip.d.ts +1 -0
  98. package/dist/utils/zip.js +17 -0
  99. package/package.json +66 -0
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Core Entity Durable Object - SQL Storage
3
+ * DO NOT MODIFY THIS FILE - You may break the entity functionality
4
+ *
5
+ * EntityDO is the per-app entity storage system backed by native SQLite.
6
+ * All entities of the same type share one DO instance, keyed by entity ID.
7
+ *
8
+ * Features:
9
+ * - SQL-backed document storage with versioning (CAS operations)
10
+ * - Server-side query, search, sort, count via json_extract()
11
+ * - Security: field name validation, LIKE escaping, input limits
12
+ * - Auto-migration from legacy KV storage
13
+ *
14
+ * NO SCHEDULING - Use SchedulerDO for scheduled jobs
15
+ */
16
+ import { DurableObject } from 'cloudflare:workers';
17
+ import type { Env } from './core-utils';
18
+ export declare const SAFE_FIELD_NAME: RegExp;
19
+ export declare function validateFieldName(field: string): string;
20
+ export declare function escapeLikePattern(input: string): string;
21
+ export declare const QUERY_LIMITS: {
22
+ MAX_SEARCH_LENGTH: number;
23
+ MAX_FILTER_COUNT: number;
24
+ MAX_SEARCH_FIELDS: number;
25
+ MAX_LIMIT: number;
26
+ MAX_DATA_SIZE: number;
27
+ };
28
+ interface QueryOptions {
29
+ limit?: number;
30
+ offset?: number;
31
+ cursor?: string | null;
32
+ filters?: Record<string, unknown>;
33
+ search?: {
34
+ query: string;
35
+ fields: string[];
36
+ };
37
+ sort?: {
38
+ field: string;
39
+ order: 'asc' | 'desc';
40
+ };
41
+ }
42
+ interface QueryResult {
43
+ items: Array<{
44
+ key: string;
45
+ v: number;
46
+ data: unknown;
47
+ }>;
48
+ total: number;
49
+ hasMore: boolean;
50
+ next: string | null;
51
+ }
52
+ /**
53
+ * Versioned document type for entity storage
54
+ */
55
+ export type Doc<T> = {
56
+ v: number;
57
+ data: T;
58
+ };
59
+ /**
60
+ * EntityDO - Per-app entity storage with SQL queries
61
+ *
62
+ * This Durable Object provides:
63
+ * - Document storage with optimistic concurrency (CAS) via SQLite
64
+ * - Query with search, sort, filter, pagination via json_extract()
65
+ * - Count with optional filters
66
+ * - Security validation on all field names
67
+ */
68
+ export declare class EntityDO extends DurableObject<Env> {
69
+ ctx: DurableObjectState;
70
+ env: Env;
71
+ private _tableReady;
72
+ private _migrationDone;
73
+ constructor(ctx: DurableObjectState, env: Env);
74
+ private ensureTable;
75
+ private migrateFromKV;
76
+ getDoc(key: string): {
77
+ v: number;
78
+ data: unknown;
79
+ } | null;
80
+ casPut(key: string, expectedV: number, data: unknown): {
81
+ ok: boolean;
82
+ v: number;
83
+ };
84
+ del(key: string): boolean;
85
+ has(key: string): boolean;
86
+ queryEntities(options?: QueryOptions): QueryResult;
87
+ countEntities(filters?: Record<string, unknown>): number;
88
+ bulkCreate(items: Array<{
89
+ key: string;
90
+ data: unknown;
91
+ }>): Array<{
92
+ key: string;
93
+ v: number;
94
+ data: unknown;
95
+ }>;
96
+ bulkUpdate(updates: Array<{
97
+ key: string;
98
+ data: Record<string, unknown>;
99
+ }>): Array<{
100
+ key: string;
101
+ ok: boolean;
102
+ v: number;
103
+ data: unknown;
104
+ }>;
105
+ bulkDelete(keys: string[]): number;
106
+ exportAll(): Array<{
107
+ key: string;
108
+ v: number;
109
+ data: unknown;
110
+ }>;
111
+ importAll(items: Array<{
112
+ key: string;
113
+ v: number;
114
+ data: unknown;
115
+ }>): {
116
+ imported: number;
117
+ };
118
+ }
119
+ export {};
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Core Events
3
+ * DO NOT MODIFY THIS FILE - You may break the project functionality
4
+ *
5
+ * This module provides:
6
+ * - emitEvent(): Fire-and-forget event emission to the workspace event stream
7
+ * - flog(): Structured logging that outputs JSON to sandbox stdout
8
+ *
9
+ * Events appear in the workspace activity feed and channel views.
10
+ * When running outside a workspace (standalone mode), calls are silently skipped.
11
+ */
12
+ export interface EmitEventParams {
13
+ type: string;
14
+ entityType?: string;
15
+ entityId?: string;
16
+ summary: string;
17
+ metadata?: Record<string, unknown>;
18
+ }
19
+ interface EventEnv {
20
+ WORKSPACE_API_URL?: string;
21
+ WORKSPACE_API_KEY?: string;
22
+ WORKSPACE_ID?: string;
23
+ APP_ID?: string;
24
+ APP_NAME?: string;
25
+ DEPLOYMENT_MODE?: 'preview' | 'production';
26
+ WorkspaceObject?: DurableObjectNamespace;
27
+ }
28
+ /**
29
+ * Any context that supports waitUntil - compatible with both
30
+ * ExecutionContext (Hono route handlers) and DurableObjectState (DOs).
31
+ */
32
+ type WaitUntilContext = Pick<ExecutionContext, 'waitUntil'>;
33
+ /**
34
+ * Convert an app name to a kebab-case channel name.
35
+ * "My Cool App" -> "my-cool-app"
36
+ */
37
+ export declare function toChannelName(appName: string): string;
38
+ /**
39
+ * Structured log entry for sandbox stdout.
40
+ * Outputs JSON with a consistent schema so the platform can parse and display
41
+ * these entries in the observability timeline.
42
+ */
43
+ export declare function flog(level: 'info' | 'warn' | 'error', system: string, message: string, data?: Record<string, unknown>): void;
44
+ /**
45
+ * Emit an event to the workspace unified event stream.
46
+ * Fire-and-forget: uses ctx.waitUntil so it doesn't block the response.
47
+ * Silently skips if workspace env vars are not configured (standalone mode).
48
+ *
49
+ * Automatically routes events to a channel derived from APP_NAME when available.
50
+ */
51
+ export declare function emitEvent(ctx: WaitUntilContext, env: EventEnv, event: EmitEventParams): void;
52
+ export {};
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Core File Storage Utilities for R2
3
+ * DO NOT MODIFY THIS FILE - You may break the project functionality
4
+ *
5
+ * This module provides the FileStorageClient class for R2 bucket operations.
6
+ * Use the FileStorageClient to upload, download, delete, and list files.
7
+ * Presigned URLs are generated via the platform API (vibe-apps don't have R2 credentials).
8
+ */
9
+ import { type Env } from './core-utils';
10
+ import type { FileMetadata, UploadOptions, DownloadOptions, ListFilesOptions, ListFilesResult, PresignedUrlRequest, PresignedUrlResponse } from './shared/core-types';
11
+ export type { FileMetadata, UploadOptions, DownloadOptions, ListFilesOptions, ListFilesResult, PresignedUrlRequest, PresignedUrlResponse, };
12
+ /**
13
+ * FileStorageClient - Wrapper for R2 bucket operations
14
+ *
15
+ * Use this client to:
16
+ * - Upload files directly to R2 (for smaller files via worker)
17
+ * - Download files directly from R2
18
+ * - List and manage files in the bucket
19
+ * - Get presigned URLs for direct R2 access (via platform API)
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const storage = createFileStorageClient(env);
24
+ *
25
+ * // Upload a file
26
+ * const metadata = await storage.upload(fileData, {
27
+ * name: 'document.pdf',
28
+ * contentType: 'application/pdf'
29
+ * });
30
+ *
31
+ * // Get presigned URL for large file download
32
+ * const { url } = await storage.getPresignedDownloadUrl('path/to/file.pdf');
33
+ *
34
+ * // List files
35
+ * const { files, cursor } = await storage.list({ prefix: 'uploads/' });
36
+ * ```
37
+ */
38
+ export declare class FileStorageClient {
39
+ private env;
40
+ private readonly bucket;
41
+ private readonly platformBaseUrl;
42
+ private readonly workspaceApiKey;
43
+ private readonly appId;
44
+ constructor(env: Env);
45
+ private extractOrigin;
46
+ /**
47
+ * Check if file storage is configured (R2 bucket bound)
48
+ */
49
+ isConfigured(): boolean;
50
+ /**
51
+ * Check if presigned URL generation is available (platform API configured)
52
+ */
53
+ canGeneratePresignedUrls(): boolean;
54
+ /**
55
+ * Generate a unique key for file storage
56
+ */
57
+ private generateKey;
58
+ /**
59
+ * Upload a file to R2
60
+ * For smaller files that can be processed through the worker.
61
+ * For large files, use getPresignedUploadUrl() for direct R2 upload.
62
+ *
63
+ * @example
64
+ * ```typescript
65
+ * const metadata = await storage.upload(fileBuffer, {
66
+ * name: 'report.pdf',
67
+ * contentType: 'application/pdf',
68
+ * customMetadata: { department: 'sales' }
69
+ * });
70
+ * console.log('Uploaded:', metadata.key);
71
+ * ```
72
+ */
73
+ upload(data: ReadableStream | ArrayBuffer | string | Blob, options?: UploadOptions): Promise<FileMetadata>;
74
+ /**
75
+ * Download a file from R2
76
+ * Returns the R2ObjectBody which includes the body stream and metadata.
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const object = await storage.download('path/to/file.pdf');
81
+ * if (object) {
82
+ * return new Response(object.body, {
83
+ * headers: { 'Content-Type': object.httpMetadata?.contentType || 'application/octet-stream' }
84
+ * });
85
+ * }
86
+ * ```
87
+ */
88
+ download(key: string, options?: DownloadOptions): Promise<R2ObjectBody | null>;
89
+ /**
90
+ * Delete a file from R2
91
+ * Returns true if the file existed, false otherwise.
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * const deleted = await storage.delete('path/to/file.pdf');
96
+ * console.log(deleted ? 'File deleted' : 'File did not exist');
97
+ * ```
98
+ */
99
+ delete(key: string): Promise<boolean>;
100
+ /**
101
+ * Delete multiple files from R2
102
+ *
103
+ * @example
104
+ * ```typescript
105
+ * await storage.deleteMany(['file1.pdf', 'file2.pdf', 'file3.pdf']);
106
+ * ```
107
+ */
108
+ deleteMany(keys: string[]): Promise<void>;
109
+ /**
110
+ * List files in R2 with optional prefix and pagination
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * // List all files in uploads/ folder
115
+ * const { files, cursor, truncated } = await storage.list({
116
+ * prefix: 'uploads/',
117
+ * limit: 100
118
+ * });
119
+ *
120
+ * // Paginate through results
121
+ * if (truncated && cursor) {
122
+ * const nextPage = await storage.list({ prefix: 'uploads/', cursor });
123
+ * }
124
+ * ```
125
+ */
126
+ list(options?: ListFilesOptions): Promise<ListFilesResult>;
127
+ /**
128
+ * Get file metadata without downloading the file content
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * const metadata = await storage.getMetadata('path/to/file.pdf');
133
+ * if (metadata) {
134
+ * console.log(`File size: ${metadata.size} bytes`);
135
+ * }
136
+ * ```
137
+ */
138
+ getMetadata(key: string): Promise<FileMetadata | null>;
139
+ /**
140
+ * Check if a file exists in R2
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * if (await storage.exists('path/to/file.pdf')) {
145
+ * console.log('File exists');
146
+ * }
147
+ * ```
148
+ */
149
+ exists(key: string): Promise<boolean>;
150
+ /**
151
+ * Get a presigned URL for uploading a file directly to R2
152
+ * The URL is generated by the platform API (vibe-apps don't have R2 credentials).
153
+ * Use this for large file uploads to avoid worker memory/CPU limits.
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * const { url, expiresAt } = await storage.getPresignedUploadUrl('uploads/large-video.mp4', {
158
+ * contentType: 'video/mp4',
159
+ * expiresIn: 3600 // 1 hour
160
+ * });
161
+ *
162
+ * // Client can now PUT directly to this URL
163
+ * await fetch(url, { method: 'PUT', body: fileData });
164
+ * ```
165
+ */
166
+ getPresignedUploadUrl(key: string, options?: {
167
+ contentType?: string;
168
+ expiresIn?: number;
169
+ }): Promise<PresignedUrlResponse>;
170
+ /**
171
+ * Get a presigned URL for downloading a file directly from R2
172
+ * The URL is generated by the platform API (vibe-apps don't have R2 credentials).
173
+ * Use this for large file downloads to avoid worker memory/CPU limits.
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * const { url, expiresAt } = await storage.getPresignedDownloadUrl('path/to/large-file.zip');
178
+ *
179
+ * // Redirect user to presigned URL or return it to client
180
+ * return Response.redirect(url, 302);
181
+ * ```
182
+ */
183
+ getPresignedDownloadUrl(key: string, options?: {
184
+ expiresIn?: number;
185
+ }): Promise<PresignedUrlResponse>;
186
+ }
187
+ /**
188
+ * Create a FileStorageClient instance
189
+ *
190
+ * @example
191
+ * ```typescript
192
+ * import { createFileStorageClient } from './core-file-storage';
193
+ *
194
+ * app.post('/api/files/upload', async (c) => {
195
+ * const storage = createFileStorageClient(c.env);
196
+ * const formData = await c.req.formData();
197
+ * const file = formData.get('file') as File;
198
+ *
199
+ * const metadata = await storage.upload(file.stream(), {
200
+ * name: file.name,
201
+ * contentType: file.type
202
+ * });
203
+ *
204
+ * return c.json({ success: true, data: metadata });
205
+ * });
206
+ * ```
207
+ */
208
+ export declare function createFileStorageClient(env: Env): FileStorageClient;
209
+ import type { Hono } from 'hono';
210
+ /**
211
+ * Mount file storage routes on the Hono app
212
+ * Provides REST API for R2 bucket operations
213
+ */
214
+ export declare function fileStorageRoutes(app: Hono<{
215
+ Bindings: Env;
216
+ }>): void;
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Core Integration Entity Utilities
3
+ * DO NOT MODIFY THIS FILE - You may break the integration entity functionality
4
+ *
5
+ * This module provides the IntegrationEntity base class for entities that are backed
6
+ * by external integrations (HubSpot, GitHub, Salesforce, etc.) instead of local storage.
7
+ *
8
+ * IntegrationEntity implements the unified EntityClass interface with EntityContext.
9
+ * All CRUD operations take ctx as the first parameter, matching the Entity class pattern.
10
+ */
11
+ import type { EntityContext, ListOptions, PaginatedResult, EntityClass } from './core-entities';
12
+ import type { Env } from './core-utils';
13
+ export interface OperationConfig {
14
+ /** API endpoint path (use :id for ID placeholder) */
15
+ endpoint: string;
16
+ }
17
+ export interface IntegrationEntityConfig {
18
+ /** Integration identifier: "hubspot", "github", "salesforce", etc. */
19
+ integrationId: string;
20
+ /** Nango provider config key: "hubspot", "github", etc. */
21
+ providerConfigKey: string;
22
+ operations: {
23
+ list?: OperationConfig;
24
+ get?: OperationConfig;
25
+ create?: OperationConfig;
26
+ update?: OperationConfig;
27
+ delete?: OperationConfig;
28
+ };
29
+ }
30
+ /**
31
+ * Extract the entity data type from an IntegrationEntity constructor.
32
+ * e.g., IntegrationEntityData<typeof ContactEntity> = HubSpotContact
33
+ */
34
+ type IntegrationEntityData<T> = T extends abstract new (...args: unknown[]) => IntegrationEntity<infer D> ? D : never;
35
+ /**
36
+ * Base constructor type for IntegrationEntity subclasses
37
+ */
38
+ type IntegrationEntityCtor = abstract new (...args: unknown[]) => IntegrationEntity<{
39
+ id: string;
40
+ }>;
41
+ /**
42
+ * Constructor with required static properties.
43
+ * This ensures the calling class has entityName, config, etc.
44
+ */
45
+ type IntegrationEntityCtorWithConfig<TCtor> = TCtor & {
46
+ entityName: string;
47
+ config: IntegrationEntityConfig;
48
+ schema?: Record<string, unknown>;
49
+ getConnectionId(env: Env | Record<string, unknown>): string | undefined;
50
+ };
51
+ /**
52
+ * IntegrationEntityClass type - for type checking integration entity classes
53
+ */
54
+ export interface IntegrationEntityClass<T extends {
55
+ id: string;
56
+ } = {
57
+ id: string;
58
+ }> extends EntityClass<T> {
59
+ config: IntegrationEntityConfig;
60
+ }
61
+ /**
62
+ * IntegrationEntity - Base class for entities backed by external integrations
63
+ *
64
+ * Implements the unified EntityClass interface with EntityContext as first parameter.
65
+ * This makes IntegrationEntity and Entity have identical CRUD interfaces.
66
+ *
67
+ * Extend this class to define entities that proxy CRUD operations to external services
68
+ * like HubSpot, GitHub, Salesforce, etc. via the IntegrationClient.
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * import { IntegrationEntity, IntegrationEntityConfig } from './core-integration-entities';
73
+ *
74
+ * interface HubSpotContact {
75
+ * id: string;
76
+ * properties: { email: string; firstname: string; lastname: string };
77
+ * }
78
+ *
79
+ * export class ContactEntity extends IntegrationEntity<HubSpotContact> {
80
+ * static readonly entityName = 'hubspot_contact';
81
+ * static readonly config: IntegrationEntityConfig = {
82
+ * integrationId: 'hubspot',
83
+ * providerConfigKey: 'hubspot',
84
+ * operations: {
85
+ * list: { endpoint: '/crm/v3/objects/contacts' },
86
+ * get: { endpoint: '/crm/v3/objects/contacts/:id' },
87
+ * create: { endpoint: '/crm/v3/objects/contacts' },
88
+ * update: { endpoint: '/crm/v3/objects/contacts/:id' },
89
+ * delete: { endpoint: '/crm/v3/objects/contacts/:id' },
90
+ * },
91
+ * };
92
+ * static readonly schema = { fields: ['id', 'email', 'firstname', 'lastname'] };
93
+ * }
94
+ *
95
+ * // Usage (same pattern as Entity):
96
+ * const ctx = { env, client };
97
+ * const contacts = await ContactEntity.list(ctx, { limit: 50 });
98
+ * // contacts is PaginatedResult<HubSpotContact> - properly typed!
99
+ * const contact = await ContactEntity.get(ctx, 'contact-123');
100
+ * // contact is HubSpotContact | null - properly typed!
101
+ * ```
102
+ */
103
+ export declare abstract class IntegrationEntity<T extends {
104
+ id: string;
105
+ }> {
106
+ static readonly entityName: string;
107
+ static readonly config: IntegrationEntityConfig;
108
+ static readonly schema?: Record<string, unknown>;
109
+ /**
110
+ * Get connection ID from env var if explicitly set.
111
+ * Returns undefined when not set -- the proxy resolves connections
112
+ * dynamically via workspaceId + provider, so this is optional.
113
+ */
114
+ static getConnectionId(env: Env | Record<string, unknown>): string | undefined;
115
+ /**
116
+ * Get the IntegrationClient from context
117
+ * Throws if client is not available
118
+ */
119
+ private static getClient;
120
+ /**
121
+ * List entities from the integration with optional filters
122
+ * Filters are passed through as query parameters to the external API
123
+ * Note: Entities needing POST-based filtering should override this method
124
+ */
125
+ static list<TCtor extends IntegrationEntityCtor>(this: IntegrationEntityCtorWithConfig<TCtor>, ctx: EntityContext, options?: ListOptions): Promise<PaginatedResult<IntegrationEntityData<TCtor>>>;
126
+ /**
127
+ * Get a single entity by ID from the integration
128
+ */
129
+ static get<TCtor extends IntegrationEntityCtor>(this: IntegrationEntityCtorWithConfig<TCtor>, ctx: EntityContext, id: string): Promise<IntegrationEntityData<TCtor> | null>;
130
+ /**
131
+ * Create a new entity in the integration
132
+ */
133
+ static create<TCtor extends IntegrationEntityCtor>(this: IntegrationEntityCtorWithConfig<TCtor>, ctx: EntityContext, data: Partial<IntegrationEntityData<TCtor>>): Promise<IntegrationEntityData<TCtor>>;
134
+ /**
135
+ * Update an entity in the integration
136
+ */
137
+ static update<TCtor extends IntegrationEntityCtor>(this: IntegrationEntityCtorWithConfig<TCtor>, ctx: EntityContext, id: string, data: Partial<IntegrationEntityData<TCtor>>): Promise<IntegrationEntityData<TCtor>>;
138
+ /**
139
+ * Delete an entity from the integration
140
+ */
141
+ static delete<TCtor extends IntegrationEntityCtor>(this: IntegrationEntityCtorWithConfig<TCtor>, ctx: EntityContext, id: string): Promise<void>;
142
+ }
143
+ /**
144
+ * Type guard to check if a class is an IntegrationEntity
145
+ */
146
+ export declare function isIntegrationEntity(cls: unknown): cls is IntegrationEntityClass;
147
+ export {};
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Core Integration Utilities
3
+ * DO NOT MODIFY THIS FILE - You may break the integration functionality
4
+ *
5
+ * This module provides utilities for making API calls to third-party services
6
+ * through the platform's multi-provider integration system.
7
+ *
8
+ * Supported providers:
9
+ * - Nango: Self-hosted OAuth for 200+ APIs
10
+ * - Pipedream: Managed OAuth clients for business apps
11
+ * - AyrShare: Social media (Instagram, TikTok, Facebook, Twitter, etc.)
12
+ *
13
+ * Provider routing is automatic - the code is provider-agnostic.
14
+ * Use the IntegrationClient class to interact with connected third-party services.
15
+ */
16
+ import { type Env } from './core-utils';
17
+ import type { NangoActionResponse, NangoProxyOptions } from './shared/core-types';
18
+ export type { NangoActionResponse, NangoProxyOptions, };
19
+ /**
20
+ * Integration requirement definition
21
+ * Used in integration-requirements.ts to declare which integrations your app needs
22
+ */
23
+ export interface IntegrationRequirement {
24
+ /** Integration provider ID (e.g., 'github', 'slack', 'hubspot') */
25
+ integrationId: string;
26
+ /** Why this integration is needed */
27
+ reason: string;
28
+ /** Whether the app cannot function without this integration */
29
+ required: boolean;
30
+ }
31
+ /**
32
+ * IntegrationClient - Wrapper for making API calls through Nango proxy
33
+ *
34
+ * Nango handles OAuth authentication and proxies requests to external APIs.
35
+ *
36
+ * For structured data access, prefer IntegrationEntity classes from './core-integration-entities'.
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * const client = new IntegrationClient(env);
41
+ *
42
+ * // GET request to HubSpot API
43
+ * const contacts = await client.proxy<{ results: Contact[] }>({
44
+ * method: 'GET',
45
+ * endpoint: '/crm/v3/objects/contacts',
46
+ * providerConfigKey: 'hubspot'
47
+ * });
48
+ *
49
+ * // POST request to create a GitHub issue
50
+ * const issue = await client.proxy({
51
+ * method: 'POST',
52
+ * endpoint: '/repos/owner/repo/issues',
53
+ * providerConfigKey: 'github',
54
+ * data: { title: 'New Issue', body: 'Issue description' }
55
+ * });
56
+ * ```
57
+ */
58
+ export declare class IntegrationClient {
59
+ private env;
60
+ private readonly proxyUrl;
61
+ private readonly proxyToken;
62
+ constructor(env: Env);
63
+ /**
64
+ * Fire-and-forget event emission for integration activity.
65
+ * Does not require waitUntil context - errors are silently swallowed.
66
+ */
67
+ private fireEvent;
68
+ /**
69
+ * Check if integrations are configured
70
+ */
71
+ isConfigured(): boolean;
72
+ /**
73
+ * Check if a specific integration has a connection configured.
74
+ * The proxy resolves connections dynamically, so this returns true
75
+ * when the proxy is configured even without explicit env vars.
76
+ */
77
+ hasConnection(provider: string): boolean;
78
+ /**
79
+ * Normalize integration ID to canonical form for env var lookup.
80
+ * MUST be identical to platform's normalizeIntegrationId() in provider-config.ts.
81
+ *
82
+ * Strips provider prefixes (pd_, nango_, ayrshare_), common suffixes (-demo, _v1),
83
+ * and removes all separators for consistent cross-provider matching.
84
+ *
85
+ * Examples:
86
+ * - "pd_sendgrid" -> "sendgrid"
87
+ * - "google-drive" -> "googledrive"
88
+ * - "pd_google_drive" -> "googledrive"
89
+ * - "hubspot-demo" -> "hubspot"
90
+ */
91
+ private normalizeIntegrationId;
92
+ private getWorkspaceIntegrationId;
93
+ private getLegacyConnectionId;
94
+ /**
95
+ * Make a request to external API via platform proxy.
96
+ * Uses platformFetch which routes through WorkspaceObject DO in production
97
+ * to avoid 522 timeouts from WfP workers.
98
+ */
99
+ private makeRequest;
100
+ /**
101
+ * Make a proxy request to an external API through the integration proxy.
102
+ * Use this for all API calls to connected third-party services.
103
+ * Supports multiple providers (Nango, Pipedream, AyrShare) - routing is automatic.
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * // GET request
108
+ * const result = await client.proxy<{ results: Contact[] }>({
109
+ * method: 'GET',
110
+ * endpoint: '/crm/v3/objects/contacts',
111
+ * providerConfigKey: 'hubspot'
112
+ * });
113
+ *
114
+ * // POST request with data
115
+ * const result = await client.proxy({
116
+ * method: 'POST',
117
+ * endpoint: '/repos/owner/repo/issues',
118
+ * providerConfigKey: 'github',
119
+ * data: { title: 'Bug Report', body: 'Description' }
120
+ * });
121
+ * ```
122
+ */
123
+ proxy<T = unknown>(options: NangoProxyOptions): Promise<NangoActionResponse<T>>;
124
+ }
125
+ /**
126
+ * Create an integration client instance
127
+ *
128
+ * @example
129
+ * ```typescript
130
+ * import { createIntegrationClient } from './core-integrations';
131
+ *
132
+ * app.get('/api/hubspot/contacts', async (c) => {
133
+ * const client = createIntegrationClient(c.env);
134
+ * const result = await client.proxy<{ results: Contact[] }>({
135
+ * method: 'GET',
136
+ * endpoint: '/crm/v3/objects/contacts',
137
+ * providerConfigKey: 'hubspot'
138
+ * });
139
+ * return c.json(result);
140
+ * });
141
+ * ```
142
+ */
143
+ export declare function createIntegrationClient(env: Env): IntegrationClient;