@nextsparkjs/plugin-social-media-publisher 0.1.0-beta.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/.env.example +76 -0
- package/README.md +423 -0
- package/api/social/connect/callback/route.ts +669 -0
- package/api/social/connect/route.ts +327 -0
- package/api/social/disconnect/route.ts +187 -0
- package/api/social/publish/route.ts +402 -0
- package/docs/01-getting-started/01-introduction.md +471 -0
- package/docs/01-getting-started/02-installation.md +471 -0
- package/docs/01-getting-started/03-configuration.md +515 -0
- package/docs/02-core-features/01-oauth-integration.md +501 -0
- package/docs/02-core-features/02-publishing.md +527 -0
- package/docs/02-core-features/03-token-management.md +661 -0
- package/docs/02-core-features/04-audit-logging.md +646 -0
- package/docs/03-advanced-usage/01-provider-apis.md +764 -0
- package/docs/03-advanced-usage/02-custom-integrations.md +695 -0
- package/docs/03-advanced-usage/03-per-client-architecture.md +575 -0
- package/docs/04-use-cases/01-agency-management.md +661 -0
- package/docs/04-use-cases/02-content-publishing.md +668 -0
- package/docs/04-use-cases/03-analytics-reporting.md +748 -0
- package/entities/audit-logs/audit-logs.config.ts +150 -0
- package/lib/oauth-helper.ts +167 -0
- package/lib/providers/facebook.ts +672 -0
- package/lib/providers/index.ts +21 -0
- package/lib/providers/instagram.ts +791 -0
- package/lib/validation.ts +155 -0
- package/migrations/001_social_media_tables.sql +167 -0
- package/package.json +15 -0
- package/plugin.config.ts +81 -0
- package/tsconfig.json +47 -0
- package/types/social.types.ts +171 -0
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
# Social Media Publisher Plugin Introduction
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The **Social Media Publisher Plugin** is a comprehensive OAuth-based solution for publishing content to Instagram Business and Facebook Pages. Built with enterprise-grade security and multi-client management in mind, it enables agencies and businesses to manage social media publishing for multiple clients from a single platform.
|
|
6
|
+
|
|
7
|
+
**Key Characteristics:**
|
|
8
|
+
- **Per-Client Management** - Social accounts belong to clients, not users
|
|
9
|
+
- **Secure by Design** - AES-256-GCM encryption for all OAuth tokens
|
|
10
|
+
- **Auto Token Refresh** - Automatic token renewal before expiration
|
|
11
|
+
- **Complete Audit Trail** - Immutable logging for compliance
|
|
12
|
+
- **Production-Ready** - Battle-tested OAuth implementation
|
|
13
|
+
|
|
14
|
+
## Purpose
|
|
15
|
+
|
|
16
|
+
### Primary Use Case: Agency Social Media Management
|
|
17
|
+
|
|
18
|
+
The plugin is specifically designed for **agencies and businesses managing social media for multiple clients**. Unlike traditional social media management tools where accounts belong to individual users, this plugin implements a **per-client architecture** where social media accounts are child entities of client records.
|
|
19
|
+
|
|
20
|
+
**This means:**
|
|
21
|
+
- Each client can have multiple Instagram Business or Facebook Page accounts
|
|
22
|
+
- Social accounts are managed within the client context
|
|
23
|
+
- Users manage social platforms through client relationships
|
|
24
|
+
- Perfect for agencies serving multiple brands
|
|
25
|
+
|
|
26
|
+
## Key Features
|
|
27
|
+
|
|
28
|
+
### 1. Per-Client Multi-Account Support
|
|
29
|
+
|
|
30
|
+
**Child Entity Architecture:**
|
|
31
|
+
- Social platforms stored as `clients_social_platforms` (child entity)
|
|
32
|
+
- Multiple Instagram Business accounts per client
|
|
33
|
+
- Multiple Facebook Page accounts per client
|
|
34
|
+
- Isolated per client (no cross-contamination)
|
|
35
|
+
|
|
36
|
+
**Benefits:**
|
|
37
|
+
- Clear client-account ownership
|
|
38
|
+
- Easy client offboarding (delete client = delete accounts)
|
|
39
|
+
- Organized multi-client management
|
|
40
|
+
- Scalable for agencies with hundreds of clients
|
|
41
|
+
|
|
42
|
+
### 2. Dual Platform Support
|
|
43
|
+
|
|
44
|
+
**Instagram Business API:**
|
|
45
|
+
- Photo publishing (2-step container process)
|
|
46
|
+
- Video publishing (with processing wait)
|
|
47
|
+
- Account insights and analytics
|
|
48
|
+
- Media performance tracking
|
|
49
|
+
- Follower statistics
|
|
50
|
+
|
|
51
|
+
**Facebook Pages API:**
|
|
52
|
+
- Text posts
|
|
53
|
+
- Photo posts
|
|
54
|
+
- Link posts with previews
|
|
55
|
+
- Page insights and analytics
|
|
56
|
+
- Fan count and engagement metrics
|
|
57
|
+
|
|
58
|
+
**Both Platforms:**
|
|
59
|
+
- Managed through single unified interface
|
|
60
|
+
- Consistent API patterns
|
|
61
|
+
- Shared OAuth flow (Facebook OAuth)
|
|
62
|
+
- Same security model
|
|
63
|
+
|
|
64
|
+
### 3. Secure Token Storage
|
|
65
|
+
|
|
66
|
+
**AES-256-GCM Encryption:**
|
|
67
|
+
```
|
|
68
|
+
Token Format: encrypted:iv:keyId
|
|
69
|
+
Example: a3f9b2...c8d1:9f7e3a...b5c2:key_2024_01
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Security Features:**
|
|
73
|
+
- Never store tokens in plain text
|
|
74
|
+
- Unique IV (Initialization Vector) per token
|
|
75
|
+
- Key versioning for rotation
|
|
76
|
+
- Encrypted at rest in database
|
|
77
|
+
- Decrypted only when needed for API calls
|
|
78
|
+
|
|
79
|
+
**Encryption Process:**
|
|
80
|
+
1. OAuth token received from Facebook
|
|
81
|
+
2. Encrypted with AES-256-GCM algorithm
|
|
82
|
+
3. IV and keyId stored alongside encrypted data
|
|
83
|
+
4. Format: `encrypted:iv:keyId`
|
|
84
|
+
5. Stored in `clients_social_platforms.accessToken`
|
|
85
|
+
|
|
86
|
+
### 4. Automatic Token Refresh
|
|
87
|
+
|
|
88
|
+
**Proactive Refresh Strategy:**
|
|
89
|
+
- Tokens checked before every publish operation
|
|
90
|
+
- Auto-refresh if < 10 minutes until expiration
|
|
91
|
+
- Uses Meta's token exchange endpoint
|
|
92
|
+
- Re-encrypts refreshed tokens
|
|
93
|
+
- Updates database automatically
|
|
94
|
+
- Zero downtime for users
|
|
95
|
+
|
|
96
|
+
**Refresh Flow:**
|
|
97
|
+
```
|
|
98
|
+
1. Check token expiration
|
|
99
|
+
2. If < 10 min → trigger refresh
|
|
100
|
+
3. Call Meta token exchange API
|
|
101
|
+
4. Receive new long-lived token (60 days)
|
|
102
|
+
5. Encrypt new token
|
|
103
|
+
6. Update database
|
|
104
|
+
7. Continue with publish operation
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Benefits:**
|
|
108
|
+
- Prevents publish failures due to expired tokens
|
|
109
|
+
- No manual token management needed
|
|
110
|
+
- Transparent to end users
|
|
111
|
+
- Automatic for all connected accounts
|
|
112
|
+
|
|
113
|
+
### 5. Complete Audit Trail
|
|
114
|
+
|
|
115
|
+
**Immutable Audit Logs:**
|
|
116
|
+
- Every action logged permanently
|
|
117
|
+
- Cannot be modified or deleted
|
|
118
|
+
- Full user attribution
|
|
119
|
+
- IP address and User-Agent tracking
|
|
120
|
+
- Timestamp for all events
|
|
121
|
+
|
|
122
|
+
**Actions Tracked:**
|
|
123
|
+
- `account_connected` - OAuth connection completed
|
|
124
|
+
- `account_disconnected` - Account removed
|
|
125
|
+
- `post_published` - Content successfully published
|
|
126
|
+
- `post_failed` - Publish attempt failed
|
|
127
|
+
- `token_refreshed` - Automatic token renewal
|
|
128
|
+
|
|
129
|
+
**Audit Log Schema:**
|
|
130
|
+
```sql
|
|
131
|
+
id UUID
|
|
132
|
+
userId TEXT (who performed action)
|
|
133
|
+
accountId UUID (which social account)
|
|
134
|
+
action TEXT (what happened)
|
|
135
|
+
details JSONB (full context)
|
|
136
|
+
ipAddress TEXT
|
|
137
|
+
userAgent TEXT
|
|
138
|
+
createdAt TIMESTAMPTZ
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Use Cases:**
|
|
142
|
+
- Compliance reporting
|
|
143
|
+
- Client billing
|
|
144
|
+
- Error investigation
|
|
145
|
+
- Usage analytics
|
|
146
|
+
- Security auditing
|
|
147
|
+
|
|
148
|
+
## Architecture Overview
|
|
149
|
+
|
|
150
|
+
### Per-Client Social Platform Management
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
Client (Parent Entity)
|
|
154
|
+
└── Social Platforms (Child Entity)
|
|
155
|
+
├── Instagram Business Account #1
|
|
156
|
+
├── Instagram Business Account #2
|
|
157
|
+
├── Facebook Page #1
|
|
158
|
+
└── Facebook Page #2
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Database Structure:**
|
|
162
|
+
```sql
|
|
163
|
+
clients
|
|
164
|
+
id UUID PRIMARY KEY
|
|
165
|
+
|
|
166
|
+
clients_social_platforms
|
|
167
|
+
id UUID PRIMARY KEY
|
|
168
|
+
parentId UUID → clients(id) -- Client owner
|
|
169
|
+
platform TEXT -- 'instagram_business' | 'facebook_page'
|
|
170
|
+
platformAccountId TEXT -- Instagram/Facebook account ID
|
|
171
|
+
platformAccountName TEXT -- @username or Page name
|
|
172
|
+
accessToken TEXT -- Encrypted token
|
|
173
|
+
tokenExpiresAt TIMESTAMPTZ -- Expiration date
|
|
174
|
+
permissions JSONB -- OAuth scopes granted
|
|
175
|
+
accountMetadata JSONB -- Profile pic, follower count, etc.
|
|
176
|
+
isActive BOOLEAN -- Soft delete flag
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### OAuth Flow Architecture
|
|
180
|
+
|
|
181
|
+
**1. Initiate OAuth:**
|
|
182
|
+
```
|
|
183
|
+
User clicks "Connect Instagram"
|
|
184
|
+
↓
|
|
185
|
+
/api/v1/plugin/social-media-publisher/social/connect?platform=instagram_business&clientId={uuid}
|
|
186
|
+
↓
|
|
187
|
+
Redirect to Facebook OAuth with state parameter
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**2. User Authorization:**
|
|
191
|
+
```
|
|
192
|
+
Facebook/Instagram authorization page
|
|
193
|
+
↓
|
|
194
|
+
User grants permissions
|
|
195
|
+
↓
|
|
196
|
+
Facebook redirects to callback URL
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**3. Callback Processing:**
|
|
200
|
+
```
|
|
201
|
+
/api/v1/plugin/social-media-publisher/social/connect/callback?code={code}&state={state}
|
|
202
|
+
↓
|
|
203
|
+
Exchange code for access token
|
|
204
|
+
↓
|
|
205
|
+
Fetch connected Instagram/Facebook accounts
|
|
206
|
+
↓
|
|
207
|
+
Encrypt tokens (AES-256-GCM)
|
|
208
|
+
↓
|
|
209
|
+
Store in clients_social_platforms table
|
|
210
|
+
↓
|
|
211
|
+
Return success HTML with postMessage
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**4. Client Updates:**
|
|
215
|
+
```
|
|
216
|
+
Popup sends postMessage to parent window
|
|
217
|
+
↓
|
|
218
|
+
Parent window receives success message
|
|
219
|
+
↓
|
|
220
|
+
Refresh page to show newly connected accounts
|
|
221
|
+
↓
|
|
222
|
+
Popup auto-closes after 2 seconds
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Publishing Architecture
|
|
226
|
+
|
|
227
|
+
**Publishing Flow:**
|
|
228
|
+
```
|
|
229
|
+
1. User selects client
|
|
230
|
+
2. User chooses social account (from client's accounts)
|
|
231
|
+
3. User uploads image and writes caption
|
|
232
|
+
4. POST /api/v1/plugin/social-media-publisher/social/publish
|
|
233
|
+
5. Plugin checks token expiration
|
|
234
|
+
6. Auto-refresh if needed (< 10 min)
|
|
235
|
+
7. Decrypt token
|
|
236
|
+
8. Call Instagram/Facebook API
|
|
237
|
+
9. Handle 2-step container process (Instagram)
|
|
238
|
+
10. Create audit log
|
|
239
|
+
11. Return result
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**Token Security Flow:**
|
|
243
|
+
```
|
|
244
|
+
Database (encrypted)
|
|
245
|
+
↓
|
|
246
|
+
Read encrypted token
|
|
247
|
+
↓
|
|
248
|
+
Decrypt with AES-256-GCM
|
|
249
|
+
↓
|
|
250
|
+
Use in API call
|
|
251
|
+
↓
|
|
252
|
+
Never logged or stored in plain text
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Use Cases
|
|
256
|
+
|
|
257
|
+
### 1. Social Media Agency
|
|
258
|
+
|
|
259
|
+
**Scenario:** Agency managing social media for 50+ clients
|
|
260
|
+
|
|
261
|
+
**Implementation:**
|
|
262
|
+
- Each client record in system
|
|
263
|
+
- Clients connect their Instagram/Facebook accounts
|
|
264
|
+
- Agency team publishes on behalf of clients
|
|
265
|
+
- Audit logs for billing and compliance
|
|
266
|
+
- Token refresh happens automatically
|
|
267
|
+
- No manual token management
|
|
268
|
+
|
|
269
|
+
**Benefits:**
|
|
270
|
+
- Organized multi-client structure
|
|
271
|
+
- Clear account ownership
|
|
272
|
+
- Easy client onboarding/offboarding
|
|
273
|
+
- Complete audit trail for billing
|
|
274
|
+
|
|
275
|
+
### 2. Multi-Brand Business
|
|
276
|
+
|
|
277
|
+
**Scenario:** Company with 10 different brands, each with social presence
|
|
278
|
+
|
|
279
|
+
**Implementation:**
|
|
280
|
+
- Each brand as a "client" in system
|
|
281
|
+
- Brand managers connect brand accounts
|
|
282
|
+
- Centralized publishing platform
|
|
283
|
+
- Consistent security and audit
|
|
284
|
+
- Shared publishing workflows
|
|
285
|
+
|
|
286
|
+
**Benefits:**
|
|
287
|
+
- Unified management interface
|
|
288
|
+
- Brand isolation (no cross-posting accidents)
|
|
289
|
+
- Consistent branding per client
|
|
290
|
+
- Enterprise security
|
|
291
|
+
|
|
292
|
+
### 3. White-Label Social Media Platform
|
|
293
|
+
|
|
294
|
+
**Scenario:** SaaS platform offering social media management to end users
|
|
295
|
+
|
|
296
|
+
**Implementation:**
|
|
297
|
+
- End users = "clients" in system
|
|
298
|
+
- Users connect their own accounts
|
|
299
|
+
- Platform provides publishing interface
|
|
300
|
+
- Token encryption built-in
|
|
301
|
+
- Audit logs for platform analytics
|
|
302
|
+
|
|
303
|
+
**Benefits:**
|
|
304
|
+
- Production-ready OAuth
|
|
305
|
+
- Security out of the box
|
|
306
|
+
- Scalable architecture
|
|
307
|
+
- Compliance-ready
|
|
308
|
+
|
|
309
|
+
## Real-World Benefits
|
|
310
|
+
|
|
311
|
+
### For Agencies
|
|
312
|
+
|
|
313
|
+
✅ **Client Management** - Clear per-client account organization
|
|
314
|
+
✅ **Security** - Enterprise-grade token encryption
|
|
315
|
+
✅ **Compliance** - Complete audit trail
|
|
316
|
+
✅ **Reliability** - Auto token refresh prevents failures
|
|
317
|
+
✅ **Scalability** - Handle hundreds of clients
|
|
318
|
+
|
|
319
|
+
### For Developers
|
|
320
|
+
|
|
321
|
+
✅ **OAuth Handled** - Complete OAuth flow implemented
|
|
322
|
+
✅ **Token Security** - Encryption library included
|
|
323
|
+
✅ **API Wrappers** - Facebook/Instagram APIs abstracted
|
|
324
|
+
✅ **Type Safety** - Full TypeScript support
|
|
325
|
+
✅ **Extensible** - Build custom features on top
|
|
326
|
+
|
|
327
|
+
### For End Users
|
|
328
|
+
|
|
329
|
+
✅ **Simple Connection** - One-click OAuth popup
|
|
330
|
+
✅ **Reliable Publishing** - Auto token refresh
|
|
331
|
+
✅ **Multiple Accounts** - Connect unlimited accounts per client
|
|
332
|
+
✅ **Secure** - Tokens never exposed
|
|
333
|
+
✅ **Transparent** - Clear success/error messages
|
|
334
|
+
|
|
335
|
+
## Technology Stack
|
|
336
|
+
|
|
337
|
+
### OAuth & APIs
|
|
338
|
+
|
|
339
|
+
**Facebook OAuth 2.0:**
|
|
340
|
+
- Authorization Code flow
|
|
341
|
+
- Long-lived tokens (60 days)
|
|
342
|
+
- Token exchange for refresh
|
|
343
|
+
- Popup-based authorization
|
|
344
|
+
|
|
345
|
+
**Instagram Business API:**
|
|
346
|
+
- Instagram Graph API (via Facebook)
|
|
347
|
+
- Requires Facebook Page connection
|
|
348
|
+
- 2-step container publishing
|
|
349
|
+
- Insights and analytics
|
|
350
|
+
|
|
351
|
+
**Facebook Pages API:**
|
|
352
|
+
- Facebook Graph API
|
|
353
|
+
- Direct page publishing
|
|
354
|
+
- Page insights
|
|
355
|
+
- Fan engagement metrics
|
|
356
|
+
|
|
357
|
+
### Security
|
|
358
|
+
|
|
359
|
+
**Encryption:**
|
|
360
|
+
- AES-256-GCM algorithm
|
|
361
|
+
- Unique IV per token
|
|
362
|
+
- Key versioning support
|
|
363
|
+
- NIST-approved cryptography
|
|
364
|
+
|
|
365
|
+
**Access Control:**
|
|
366
|
+
- Row-Level Security (RLS) policies
|
|
367
|
+
- User can only see own clients' accounts
|
|
368
|
+
- Postgres RLS enforcement
|
|
369
|
+
- Session-based authentication
|
|
370
|
+
|
|
371
|
+
**Audit:**
|
|
372
|
+
- Immutable logs
|
|
373
|
+
- Full attribution
|
|
374
|
+
- IP and User-Agent tracking
|
|
375
|
+
- GDPR-compliant logging
|
|
376
|
+
|
|
377
|
+
### Database
|
|
378
|
+
|
|
379
|
+
**PostgreSQL:**
|
|
380
|
+
- Parent-child entity relationships
|
|
381
|
+
- JSONB for flexible metadata
|
|
382
|
+
- RLS for access control
|
|
383
|
+
- Timestamptz for accurate time tracking
|
|
384
|
+
|
|
385
|
+
**Tables:**
|
|
386
|
+
- `clients` - Parent entity
|
|
387
|
+
- `clients_social_platforms` - Child entity (social accounts)
|
|
388
|
+
- `audit_logs` - Immutable audit trail
|
|
389
|
+
|
|
390
|
+
## Getting Started
|
|
391
|
+
|
|
392
|
+
### Quick Setup
|
|
393
|
+
|
|
394
|
+
1. **Create Facebook App** - Get OAuth credentials
|
|
395
|
+
2. **Configure Environment** - Add credentials and encryption key
|
|
396
|
+
3. **Enable Plugin** - Activate in theme config
|
|
397
|
+
4. **Connect Accounts** - OAuth flow via popup
|
|
398
|
+
5. **Start Publishing** - Use publish endpoint
|
|
399
|
+
|
|
400
|
+
### Next Steps
|
|
401
|
+
|
|
402
|
+
- **[Installation](./02-installation.md)** - Detailed setup guide
|
|
403
|
+
- **[Configuration](./03-configuration.md)** - Environment variables and OAuth setup
|
|
404
|
+
- **[OAuth Integration](../02-core-features/01-oauth-integration.md)** - Understanding the OAuth flow
|
|
405
|
+
- **[Publishing](../02-core-features/02-publishing.md)** - Start publishing content
|
|
406
|
+
|
|
407
|
+
## Key Concepts
|
|
408
|
+
|
|
409
|
+
### Per-Client Architecture
|
|
410
|
+
|
|
411
|
+
Social accounts are **child entities** of clients, not global user accounts. This means:
|
|
412
|
+
- Accounts belong to clients
|
|
413
|
+
- Users access via client relationship
|
|
414
|
+
- Clean separation of concerns
|
|
415
|
+
- Scalable for agencies
|
|
416
|
+
|
|
417
|
+
### Token Lifecycle
|
|
418
|
+
|
|
419
|
+
Tokens go through a managed lifecycle:
|
|
420
|
+
1. **Received** - From OAuth
|
|
421
|
+
2. **Encrypted** - AES-256-GCM
|
|
422
|
+
3. **Stored** - In database
|
|
423
|
+
4. **Decrypted** - Only when needed
|
|
424
|
+
5. **Refreshed** - Before expiration
|
|
425
|
+
6. **Re-encrypted** - After refresh
|
|
426
|
+
|
|
427
|
+
### Popup OAuth Pattern
|
|
428
|
+
|
|
429
|
+
OAuth uses popup window pattern:
|
|
430
|
+
- Main window stays open
|
|
431
|
+
- Popup opens for authorization
|
|
432
|
+
- User grants permissions
|
|
433
|
+
- Popup sends postMessage
|
|
434
|
+
- Main window refreshes
|
|
435
|
+
- Popup auto-closes
|
|
436
|
+
|
|
437
|
+
**Benefits:**
|
|
438
|
+
- No full-page redirects
|
|
439
|
+
- Preserves application state
|
|
440
|
+
- Better user experience
|
|
441
|
+
- Standard OAuth pattern
|
|
442
|
+
|
|
443
|
+
## Philosophy
|
|
444
|
+
|
|
445
|
+
This plugin is designed with these principles:
|
|
446
|
+
|
|
447
|
+
**Security First:**
|
|
448
|
+
- Never store plain text tokens
|
|
449
|
+
- Encryption at rest
|
|
450
|
+
- Access control via RLS
|
|
451
|
+
- Audit everything
|
|
452
|
+
|
|
453
|
+
**Agency-Focused:**
|
|
454
|
+
- Per-client management
|
|
455
|
+
- Multi-account support
|
|
456
|
+
- Scalable architecture
|
|
457
|
+
- Clear ownership
|
|
458
|
+
|
|
459
|
+
**Production-Ready:**
|
|
460
|
+
- Auto token refresh
|
|
461
|
+
- Comprehensive error handling
|
|
462
|
+
- Battle-tested OAuth
|
|
463
|
+
- Type-safe APIs
|
|
464
|
+
|
|
465
|
+
**Extensible:**
|
|
466
|
+
- Provider API wrappers
|
|
467
|
+
- TypeScript types
|
|
468
|
+
- Clear interfaces
|
|
469
|
+
- Easy to build on
|
|
470
|
+
|
|
471
|
+
The plugin provides the foundation; you build the features your business needs on top.
|