@nextsparkjs/plugin-social-media-publisher 0.1.0-beta.68 → 0.1.0-beta.72
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 +42 -42
- package/README.md +40 -0
- package/lib/plugin-env.ts +164 -0
- package/package.json +4 -4
- package/LICENSE +0 -21
package/.env.example
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
#
|
|
2
|
-
# SOCIAL MEDIA PUBLISHER PLUGIN
|
|
3
|
-
#
|
|
1
|
+
# ============================================
|
|
2
|
+
# SOCIAL MEDIA PUBLISHER PLUGIN CONFIGURATION
|
|
3
|
+
# ============================================
|
|
4
4
|
#
|
|
5
|
-
# Copy this file to .env and
|
|
5
|
+
# Copy this file to .env and configure your social media credentials
|
|
6
|
+
# This file is loaded automatically by the Social Media Publisher plugin
|
|
6
7
|
#
|
|
7
|
-
#
|
|
8
|
+
# Priority: Plugin .env > Root .env > Defaults
|
|
8
9
|
#
|
|
9
|
-
#
|
|
10
|
+
# ============================================
|
|
10
11
|
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
12
|
+
# ===========================
|
|
13
|
+
# Facebook/Meta OAuth
|
|
14
|
+
# ===========================
|
|
14
15
|
# Get from: https://developers.facebook.com/apps/
|
|
15
16
|
# App Dashboard → Settings → Basic → App ID & App Secret
|
|
16
17
|
#
|
|
@@ -23,54 +24,53 @@
|
|
|
23
24
|
# - instagram_basic
|
|
24
25
|
# - instagram_content_publish
|
|
25
26
|
# - instagram_manage_comments
|
|
26
|
-
#
|
|
27
|
-
# Redirect URI: [YOUR_APP_URL]/api/v1/plugin/social-media-publisher/social/connect/callback
|
|
28
|
-
# Example: https://yourdomain.com/api/v1/plugin/social-media-publisher/social/connect/callback
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
# Facebook App ID
|
|
29
|
+
FACEBOOK_CLIENT_ID=your-facebook-app-id
|
|
30
|
+
|
|
31
|
+
# Facebook App Secret
|
|
32
|
+
FACEBOOK_CLIENT_SECRET=your-facebook-app-secret
|
|
32
33
|
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
34
|
+
# ===========================
|
|
35
|
+
# OAuth Token Encryption
|
|
36
|
+
# ===========================
|
|
37
|
+
# Required for secure storage of OAuth tokens
|
|
38
|
+
# Generate with: openssl rand -hex 32
|
|
39
|
+
# Or: node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
+
OAUTH_ENCRYPTION_KEY=your-32-byte-hex-encryption-key
|
|
42
|
+
|
|
43
|
+
# ===========================
|
|
44
|
+
# Cron Job Authentication
|
|
45
|
+
# ===========================
|
|
46
|
+
# Secret key to authenticate scheduled publishing requests
|
|
41
47
|
# Generate with: openssl rand -base64 32
|
|
42
48
|
#
|
|
43
|
-
#
|
|
44
|
-
# POST /api/v1/cron/publish-scheduled
|
|
49
|
+
# Used by: POST /api/v1/cron/publish-scheduled
|
|
45
50
|
# Header: Authorization: Bearer <CRON_SECRET>
|
|
46
|
-
#
|
|
47
|
-
# Configure in your cron service (Vercel Cron, GitHub Actions, etc.)
|
|
48
51
|
|
|
49
|
-
CRON_SECRET=
|
|
52
|
+
CRON_SECRET=your-cron-secret-key-here
|
|
50
53
|
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
+
# ===========================
|
|
55
|
+
# Quick Setup Guide
|
|
56
|
+
# ===========================
|
|
54
57
|
#
|
|
55
|
-
# 1.
|
|
56
|
-
# cp .env.example .env
|
|
57
|
-
#
|
|
58
|
-
# 2. Create Facebook App:
|
|
58
|
+
# 1. Create Facebook App:
|
|
59
59
|
# - Go to https://developers.facebook.com/apps/
|
|
60
60
|
# - Create new app → Type: Business
|
|
61
61
|
# - Add Facebook Login & Instagram API products
|
|
62
|
-
# - Configure OAuth Redirect URIs
|
|
63
|
-
# - Copy App ID & App Secret to this file
|
|
64
62
|
#
|
|
65
|
-
#
|
|
63
|
+
# 2. Configure OAuth Redirect URI:
|
|
64
|
+
# [YOUR_APP_URL]/api/v1/plugin/social-media-publisher/social/connect/callback
|
|
65
|
+
#
|
|
66
|
+
# 3. Generate encryption key:
|
|
67
|
+
# openssl rand -hex 32
|
|
68
|
+
#
|
|
69
|
+
# 4. Generate cron secret:
|
|
66
70
|
# openssl rand -base64 32
|
|
67
71
|
#
|
|
68
|
-
#
|
|
72
|
+
# 5. For Vercel Cron (see vercel.json):
|
|
69
73
|
# - Add CRON_SECRET to Vercel Environment Variables
|
|
70
74
|
# - Cron runs every 5 minutes by default
|
|
71
75
|
#
|
|
72
|
-
#
|
|
73
|
-
# curl -X POST http://localhost:5173/api/v1/cron/publish-scheduled \
|
|
74
|
-
# -H "Authorization: Bearer YOUR_CRON_SECRET"
|
|
75
|
-
#
|
|
76
|
-
# ============================================================================
|
|
76
|
+
# ⚠️ NEVER commit .env to git - it contains secrets!
|
package/README.md
CHANGED
|
@@ -251,6 +251,46 @@ async function publishToInstagram(account: any, imageUrl: string, caption: strin
|
|
|
251
251
|
|
|
252
252
|
## Environment Variables
|
|
253
253
|
|
|
254
|
+
### ⭐ Plugin-Level Environment Configuration (Recommended)
|
|
255
|
+
|
|
256
|
+
The Social Media Publisher plugin supports **plugin-level `.env` files** that take priority over root environment variables.
|
|
257
|
+
|
|
258
|
+
#### Setup
|
|
259
|
+
|
|
260
|
+
1. **Copy the example file:**
|
|
261
|
+
```bash
|
|
262
|
+
cp contents/plugins/social-media-publisher/.env.example contents/plugins/social-media-publisher/.env
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
2. **Configure your credentials:**
|
|
266
|
+
```env
|
|
267
|
+
# Facebook/Meta OAuth
|
|
268
|
+
FACEBOOK_CLIENT_ID="your-facebook-app-id"
|
|
269
|
+
FACEBOOK_CLIENT_SECRET="your-facebook-app-secret"
|
|
270
|
+
|
|
271
|
+
# Cron Job Authentication
|
|
272
|
+
CRON_SECRET="your-cron-secret-key-here"
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
#### Priority System
|
|
276
|
+
|
|
277
|
+
The plugin environment loader uses this priority:
|
|
278
|
+
|
|
279
|
+
1. **Plugin `.env`** (`contents/plugins/social-media-publisher/.env`) - Highest priority
|
|
280
|
+
2. **Root `.env`** (`/.env`) - Fallback for variables not in plugin .env
|
|
281
|
+
3. **Built-in defaults** - Lowest priority
|
|
282
|
+
|
|
283
|
+
#### Benefits
|
|
284
|
+
|
|
285
|
+
- ✅ **Isolation**: OAuth credentials isolated to the plugin
|
|
286
|
+
- ✅ **Security**: Sensitive keys scoped to specific plugins
|
|
287
|
+
- ✅ **Modularity**: Each plugin manages its own secrets
|
|
288
|
+
- ✅ **Flexibility**: Different configs per environment
|
|
289
|
+
|
|
290
|
+
### Root Environment Variables (Alternative)
|
|
291
|
+
|
|
292
|
+
You can also configure credentials in the root `.env`:
|
|
293
|
+
|
|
254
294
|
```env
|
|
255
295
|
# Facebook App Credentials (same as Better Auth)
|
|
256
296
|
FACEBOOK_CLIENT_ID=your_app_id
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Social Media Publisher Plugin Environment Configuration (Server-Only)
|
|
3
|
+
*
|
|
4
|
+
* Uses centralized plugin environment loader from core
|
|
5
|
+
* Provides type-safe access to OAuth and publishing configuration
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { getPluginEnv } from '@nextsparkjs/core/lib/plugins/env-loader'
|
|
9
|
+
|
|
10
|
+
interface SocialMediaPublisherEnvConfig {
|
|
11
|
+
// Facebook/Meta OAuth
|
|
12
|
+
FACEBOOK_CLIENT_ID?: string
|
|
13
|
+
FACEBOOK_CLIENT_SECRET?: string
|
|
14
|
+
FACEBOOK_APP_ID?: string // Alternative name
|
|
15
|
+
FACEBOOK_APP_SECRET?: string // Alternative name
|
|
16
|
+
|
|
17
|
+
// OAuth Encryption
|
|
18
|
+
OAUTH_ENCRYPTION_KEY?: string
|
|
19
|
+
|
|
20
|
+
// Cron Job Authentication
|
|
21
|
+
CRON_SECRET?: string
|
|
22
|
+
|
|
23
|
+
// App URL
|
|
24
|
+
NEXT_PUBLIC_APP_URL?: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class PluginEnvironment {
|
|
28
|
+
private static instance: PluginEnvironment
|
|
29
|
+
private config: SocialMediaPublisherEnvConfig = {}
|
|
30
|
+
private loaded = false
|
|
31
|
+
|
|
32
|
+
private constructor() {
|
|
33
|
+
this.loadEnvironment()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public static getInstance(): PluginEnvironment {
|
|
37
|
+
if (!PluginEnvironment.instance) {
|
|
38
|
+
PluginEnvironment.instance = new PluginEnvironment()
|
|
39
|
+
}
|
|
40
|
+
return PluginEnvironment.instance
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private loadEnvironment(forceReload: boolean = false): void {
|
|
44
|
+
if (this.loaded && !forceReload) return
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
// Use centralized plugin env loader
|
|
48
|
+
const env = getPluginEnv('social-media-publisher')
|
|
49
|
+
|
|
50
|
+
this.config = {
|
|
51
|
+
// Facebook/Meta OAuth (support both naming conventions)
|
|
52
|
+
FACEBOOK_CLIENT_ID: env.FACEBOOK_CLIENT_ID || env.FACEBOOK_APP_ID,
|
|
53
|
+
FACEBOOK_CLIENT_SECRET: env.FACEBOOK_CLIENT_SECRET || env.FACEBOOK_APP_SECRET,
|
|
54
|
+
FACEBOOK_APP_ID: env.FACEBOOK_APP_ID || env.FACEBOOK_CLIENT_ID,
|
|
55
|
+
FACEBOOK_APP_SECRET: env.FACEBOOK_APP_SECRET || env.FACEBOOK_CLIENT_SECRET,
|
|
56
|
+
|
|
57
|
+
// OAuth Encryption
|
|
58
|
+
OAUTH_ENCRYPTION_KEY: env.OAUTH_ENCRYPTION_KEY,
|
|
59
|
+
|
|
60
|
+
// Cron Job Authentication
|
|
61
|
+
CRON_SECRET: env.CRON_SECRET,
|
|
62
|
+
|
|
63
|
+
// App URL
|
|
64
|
+
NEXT_PUBLIC_APP_URL: env.NEXT_PUBLIC_APP_URL,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
this.logLoadedConfiguration()
|
|
68
|
+
this.loaded = true
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error('[Social Media Publisher] Failed to load environment:', error)
|
|
71
|
+
this.loaded = true
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private logLoadedConfiguration(): void {
|
|
76
|
+
if (process.env.NODE_ENV === 'development') {
|
|
77
|
+
console.log('[Social Media Publisher] Environment Configuration:')
|
|
78
|
+
console.log(' → Facebook/Meta OAuth:')
|
|
79
|
+
console.log(` - FACEBOOK_CLIENT_ID: ${this.config.FACEBOOK_CLIENT_ID ? '✓ set' : '✗ not set'}`)
|
|
80
|
+
console.log(` - FACEBOOK_CLIENT_SECRET: ${this.config.FACEBOOK_CLIENT_SECRET ? '✓ set' : '✗ not set'}`)
|
|
81
|
+
console.log(' → OAuth Encryption:')
|
|
82
|
+
console.log(` - OAUTH_ENCRYPTION_KEY: ${this.config.OAUTH_ENCRYPTION_KEY ? '✓ set' : '✗ not set'}`)
|
|
83
|
+
console.log(' → Cron Authentication:')
|
|
84
|
+
console.log(` - CRON_SECRET: ${this.config.CRON_SECRET ? '✓ set' : '✗ not set'}`)
|
|
85
|
+
console.log(' → App Configuration:')
|
|
86
|
+
console.log(` - NEXT_PUBLIC_APP_URL: ${this.config.NEXT_PUBLIC_APP_URL || 'not set'}`)
|
|
87
|
+
console.log()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public getConfig(): SocialMediaPublisherEnvConfig {
|
|
92
|
+
if (!this.loaded) {
|
|
93
|
+
this.loadEnvironment()
|
|
94
|
+
}
|
|
95
|
+
return this.config
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Helper methods
|
|
99
|
+
public getFacebookClientId(): string | undefined {
|
|
100
|
+
return this.getConfig().FACEBOOK_CLIENT_ID
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public getFacebookClientSecret(): string | undefined {
|
|
104
|
+
return this.getConfig().FACEBOOK_CLIENT_SECRET
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public getOAuthEncryptionKey(): string | undefined {
|
|
108
|
+
return this.getConfig().OAUTH_ENCRYPTION_KEY
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public getCronSecret(): string | undefined {
|
|
112
|
+
return this.getConfig().CRON_SECRET
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public getAppUrl(): string | undefined {
|
|
116
|
+
return this.getConfig().NEXT_PUBLIC_APP_URL
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public hasFacebookCredentials(): boolean {
|
|
120
|
+
const config = this.getConfig()
|
|
121
|
+
return !!(config.FACEBOOK_CLIENT_ID && config.FACEBOOK_CLIENT_SECRET)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public hasOAuthEncryption(): boolean {
|
|
125
|
+
return !!this.getConfig().OAUTH_ENCRYPTION_KEY
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public validateEnvironment(): { valid: boolean; errors: string[] } {
|
|
129
|
+
const errors: string[] = []
|
|
130
|
+
const config = this.getConfig()
|
|
131
|
+
|
|
132
|
+
if (!config.FACEBOOK_CLIENT_ID) {
|
|
133
|
+
errors.push('FACEBOOK_CLIENT_ID is required for OAuth')
|
|
134
|
+
}
|
|
135
|
+
if (!config.FACEBOOK_CLIENT_SECRET) {
|
|
136
|
+
errors.push('FACEBOOK_CLIENT_SECRET is required for OAuth')
|
|
137
|
+
}
|
|
138
|
+
if (!config.OAUTH_ENCRYPTION_KEY) {
|
|
139
|
+
errors.push('OAUTH_ENCRYPTION_KEY is required for token encryption')
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
valid: errors.length === 0,
|
|
144
|
+
errors,
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public reload(): void {
|
|
149
|
+
this.loaded = false
|
|
150
|
+
this.loadEnvironment(true)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export const pluginEnv = PluginEnvironment.getInstance()
|
|
155
|
+
|
|
156
|
+
// Convenience exports
|
|
157
|
+
export const getFacebookClientId = () => pluginEnv.getFacebookClientId()
|
|
158
|
+
export const getFacebookClientSecret = () => pluginEnv.getFacebookClientSecret()
|
|
159
|
+
export const getOAuthEncryptionKey = () => pluginEnv.getOAuthEncryptionKey()
|
|
160
|
+
export const getCronSecret = () => pluginEnv.getCronSecret()
|
|
161
|
+
export const getAppUrl = () => pluginEnv.getAppUrl()
|
|
162
|
+
export const hasFacebookCredentials = () => pluginEnv.hasFacebookCredentials()
|
|
163
|
+
export const hasOAuthEncryption = () => pluginEnv.hasOAuthEncryption()
|
|
164
|
+
export const validateEnvironment = () => pluginEnv.validateEnvironment()
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextsparkjs/plugin-social-media-publisher",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.72",
|
|
4
4
|
"private": false,
|
|
5
5
|
"main": "./plugin.config.ts",
|
|
6
6
|
"requiredPlugins": [],
|
|
7
7
|
"dependencies": {},
|
|
8
8
|
"peerDependencies": {
|
|
9
|
+
"@nextsparkjs/core": "workspace:*",
|
|
9
10
|
"next": "^15.0.0",
|
|
10
11
|
"react": "^19.0.0",
|
|
11
12
|
"react-dom": "^19.0.0",
|
|
12
|
-
"zod": "^4.0.0"
|
|
13
|
-
"@nextsparkjs/core": "0.1.0-beta.68"
|
|
13
|
+
"zod": "^4.0.0"
|
|
14
14
|
},
|
|
15
15
|
"nextspark": {
|
|
16
16
|
"type": "plugin",
|
|
17
17
|
"name": "social-media-publisher"
|
|
18
18
|
}
|
|
19
|
-
}
|
|
19
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 NextSpark
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|