maxion-mcp-gateway 1.0.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 +3 -0
- package/.mcpbignore +3 -0
- package/.well-known/mcp/server-card.json +28 -0
- package/Cargo.lock +2578 -0
- package/Cargo.toml.bak +19 -0
- package/Deploy_Ecosystem.ps1 +31 -0
- package/May_8th_Pre_Release_Update.md +67 -0
- package/README.md +41 -0
- package/Run-Transparent.ps1 +33 -0
- package/Start-MaxionEngine.bat +7 -0
- package/Sync_WebHub.ps1 +24 -0
- package/admin_dashboard.html +238 -0
- package/admin_emulator.js +46 -0
- package/admin_host.js +126 -0
- package/ai-plugin.json +17 -0
- package/amplify.yml +17 -0
- package/apply_patches.js +91 -0
- package/aws-lambda-stripe/index.js +75 -0
- package/aws-lambda-stripe/lineage_api.js +57 -0
- package/aws-lambda-stripe/package-lock.json +298 -0
- package/aws_lambda_handler.js +301 -0
- package/build_worker_zip.js +21 -0
- package/clean_page.js +53 -0
- package/clean_page_2.js +37 -0
- package/clean_trials_safe.js +35 -0
- package/configure_aws.js +102 -0
- package/cors.json +10 -0
- package/create_lambda.js +85 -0
- package/create_mock_user.js +30 -0
- package/dashboard_server_head.js +430 -0
- package/dashboard_server_head_utf8.js +430 -0
- package/deploy_installers.js +67 -0
- package/deploy_lineage_lambda.js +36 -0
- package/deploy_maxion.js +56 -0
- package/deploy_real_lambda.js +63 -0
- package/deploy_submitter.js +25 -0
- package/deploy_web_hub.js +203 -0
- package/deploy_worker_now.js +25 -0
- package/diamonize-lsa-mcp/index.js +79 -0
- package/diamonize-lsa-mcp/package-lock.json +1161 -0
- package/diamonize-lsa-mcp/package.json +24 -0
- package/diamonize-lsa-mcp/smithery.yaml +11 -0
- package/generate_mcps.js +243 -0
- package/inject_ui.js +41 -0
- package/jk-mcp-server/index.js +245 -0
- package/jk-mcp-server/package-lock.json +1158 -0
- package/jk-mcp-server/package.json +24 -0
- package/lineage-0-vc-mcp/index.js +169 -0
- package/lineage-0-vc-mcp/package-lock.json +1161 -0
- package/lineage-0-vc-mcp/package.json +24 -0
- package/lineage-0-vc-mcp/smithery.yaml +11 -0
- package/logger.js +62 -0
- package/manifest.json +69 -0
- package/maxion-mcp/index.js +92 -0
- package/maxion-mcp/package-lock.json +1161 -0
- package/maxion-mcp/package.json +24 -0
- package/maxion-mcp/smithery.yaml +11 -0
- package/mcp_wrapper.js +195 -0
- package/outreach_leads.md +23 -0
- package/package.json +27 -0
- package/poll_test.js +30 -0
- package/quezar-storage-mcp/index.js +96 -0
- package/quezar-storage-mcp/package-lock.json +1161 -0
- package/quezar-storage-mcp/package.json +24 -0
- package/quezar-storage-mcp/smithery.yaml +11 -0
- package/scripts/calc_benchmark.ps1 +63 -0
- package/scripts/clean_aws_s3.js +71 -0
- package/scripts/diamonize_benchmark.ps1 +39 -0
- package/scripts/quezar_benchmark.ps1 +54 -0
- package/scripts/real_physical_benchmark.ps1 +74 -0
- package/scripts/run_live_benchmarks.ps1 +37 -0
- package/scripts/shatter_maxion.ps1 +34 -0
- package/scripts/social_visibility_bot.js +53 -0
- package/simulate_lead.js +30 -0
- package/smithery.yaml +31 -0
- package/test_aws_models.js +62 -0
- package/test_fallback.js +28 -0
- package/update_lambda.js +143 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
const { BedrockRuntimeClient, StartAsyncInvokeCommand, GetAsyncInvokeCommand, InvokeModelCommand } = require("@aws-sdk/client-bedrock-runtime");
|
|
2
|
+
const { S3Client, GetObjectCommand, ListObjectsV2Command, PutObjectCommand } = require("@aws-sdk/client-s3");
|
|
3
|
+
const { DynamoDBClient, PutItemCommand, QueryCommand, UpdateItemCommand, GetItemCommand } = require("@aws-sdk/client-dynamodb");
|
|
4
|
+
const { getSignedUrl } = require("@aws-sdk/s3-request-presigner");
|
|
5
|
+
|
|
6
|
+
const ddbClient = new DynamoDBClient({ region: process.env.AWS_REGION || "us-east-1" });
|
|
7
|
+
const bedrockClient = new BedrockRuntimeClient({ region: process.env.AWS_REGION || 'us-east-1' });
|
|
8
|
+
const s3Client = new S3Client({ region: process.env.AWS_REGION || 'us-east-1' });
|
|
9
|
+
|
|
10
|
+
const DDB_TABLE = "LineageUserArchive";
|
|
11
|
+
const RECEIPTS_TABLE = "LineageReceipts";
|
|
12
|
+
const S3_OUTPUT_BUCKET = process.env.S3_OUTPUT_BUCKET || 'jk-advanced-tech-web-videos';
|
|
13
|
+
const TEAK_PASSKEY = process.env.TEAK_PASSKEY || '';
|
|
14
|
+
|
|
15
|
+
const CORS = {
|
|
16
|
+
"Access-Control-Allow-Origin": "*",
|
|
17
|
+
"Access-Control-Allow-Headers": "Content-Type,Authorization",
|
|
18
|
+
"Access-Control-Allow-Methods": "OPTIONS,POST,GET"
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function respond(statusCode, obj) {
|
|
22
|
+
return { statusCode, headers: CORS, body: JSON.stringify(obj) };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function errRespond(statusCode, message, details) {
|
|
26
|
+
console.error(`[ERROR ${statusCode}]`, message, details || '');
|
|
27
|
+
return respond(statusCode, { error: message, details: details ? String(details) : undefined, timestamp: new Date().toISOString() });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ── Validate and atomically consume a one-time receipt ──────────────────────
|
|
31
|
+
// Returns { ok: true } on success, or { ok: false, reason: string } on failure.
|
|
32
|
+
// TEAK passkey bypasses all receipt checks.
|
|
33
|
+
async function consumeReceipt(receiptId) {
|
|
34
|
+
if (!receiptId) return { ok: false, reason: 'Missing receipt ID. Please complete payment first.' };
|
|
35
|
+
|
|
36
|
+
// Owner TEAK bypass — validated server-side against env var
|
|
37
|
+
if (TEAK_PASSKEY && receiptId === TEAK_PASSKEY) return { ok: true, teak: true };
|
|
38
|
+
|
|
39
|
+
// Verify the receipt exists and is unused
|
|
40
|
+
let item;
|
|
41
|
+
try {
|
|
42
|
+
const res = await ddbClient.send(new GetItemCommand({
|
|
43
|
+
TableName: RECEIPTS_TABLE,
|
|
44
|
+
Key: { receiptId: { S: receiptId } }
|
|
45
|
+
}));
|
|
46
|
+
item = res.Item;
|
|
47
|
+
} catch (e) {
|
|
48
|
+
return { ok: false, reason: 'Could not verify receipt. Please try again.' };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!item) return { ok: false, reason: 'Receipt not found. Please check your code and try again.' };
|
|
52
|
+
if (item.status?.S !== 'unused') return { ok: false, reason: 'This receipt has already been used. Each receipt allows one generation.' };
|
|
53
|
+
|
|
54
|
+
// Atomically mark as used — prevents double-spend if two requests race
|
|
55
|
+
try {
|
|
56
|
+
await ddbClient.send(new UpdateItemCommand({
|
|
57
|
+
TableName: RECEIPTS_TABLE,
|
|
58
|
+
Key: { receiptId: { S: receiptId } },
|
|
59
|
+
UpdateExpression: 'SET #s = :used, usedAt = :now',
|
|
60
|
+
ConditionExpression: '#s = :unused',
|
|
61
|
+
ExpressionAttributeNames: { '#s': 'status' },
|
|
62
|
+
ExpressionAttributeValues: {
|
|
63
|
+
':used': { S: 'used' },
|
|
64
|
+
':now': { S: new Date().toISOString() },
|
|
65
|
+
':unused': { S: 'unused' },
|
|
66
|
+
}
|
|
67
|
+
}));
|
|
68
|
+
} catch (e) {
|
|
69
|
+
// ConditionalCheckFailedException means another request just consumed it
|
|
70
|
+
return { ok: false, reason: 'This receipt has already been used. Each receipt allows one generation.' };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { ok: true };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
exports.handler = async (event) => {
|
|
77
|
+
const method = event.httpMethod || event.requestContext?.http?.method || 'POST';
|
|
78
|
+
const rawPath = event.path || event.rawPath || '/';
|
|
79
|
+
console.log('[Lambda] method:', method, 'path:', rawPath);
|
|
80
|
+
if (method === 'OPTIONS') return respond(200, {});
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
const body = JSON.parse(event.body || '{}');
|
|
84
|
+
const receiptId = body.receiptId;
|
|
85
|
+
|
|
86
|
+
// ── GET /receipt?sessionId= ─────────────────────────────────────────
|
|
87
|
+
// Called by the frontend after Stripe redirects back with ?session_id=
|
|
88
|
+
// Returns the RC_ code so the user can copy and enter it.
|
|
89
|
+
if (method === 'GET' && rawPath.includes('/receipt')) {
|
|
90
|
+
const sessionId = event.queryStringParameters?.sessionId;
|
|
91
|
+
if (!sessionId) return errRespond(400, 'Missing sessionId');
|
|
92
|
+
|
|
93
|
+
// Scan for the receipt by sessionId (low volume table, acceptable)
|
|
94
|
+
const scanRes = await ddbClient.send(new QueryCommand({
|
|
95
|
+
TableName: RECEIPTS_TABLE,
|
|
96
|
+
IndexName: 'sessionId-index',
|
|
97
|
+
KeyConditionExpression: 'sessionId = :s',
|
|
98
|
+
ExpressionAttributeValues: { ':s': { S: sessionId } }
|
|
99
|
+
}));
|
|
100
|
+
|
|
101
|
+
const item = scanRes.Items?.[0];
|
|
102
|
+
if (!item) return errRespond(404, 'Receipt not found for this session. It may still be processing — try again in a moment.');
|
|
103
|
+
return respond(200, {
|
|
104
|
+
receiptId: item.receiptId?.S,
|
|
105
|
+
status: item.status?.S,
|
|
106
|
+
email: item.email?.S,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ── GET /verify?receiptId= ──────────────────────────────────────────
|
|
111
|
+
// Validates a code without consuming it — called by frontend VERIFY button.
|
|
112
|
+
if (method === 'GET' && rawPath.includes('/verify')) {
|
|
113
|
+
const qReceiptId = event.queryStringParameters?.receiptId;
|
|
114
|
+
if (!qReceiptId) return errRespond(400, 'Missing receiptId');
|
|
115
|
+
|
|
116
|
+
// TEAK owner bypass
|
|
117
|
+
if (TEAK_PASSKEY && qReceiptId === TEAK_PASSKEY) return respond(200, { valid: true, teak: true });
|
|
118
|
+
|
|
119
|
+
const res = await ddbClient.send(new GetItemCommand({
|
|
120
|
+
TableName: RECEIPTS_TABLE,
|
|
121
|
+
Key: { receiptId: { S: qReceiptId } }
|
|
122
|
+
}));
|
|
123
|
+
const item = res.Item;
|
|
124
|
+
if (!item) return respond(200, { valid: false, reason: 'Receipt not found.' });
|
|
125
|
+
if (item.status?.S !== 'unused') return respond(200, { valid: false, reason: 'This receipt has already been used.' });
|
|
126
|
+
return respond(200, { valid: true });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ── GET /history ────────────────────────────────────────────────────
|
|
130
|
+
if (method === 'GET' && rawPath.includes('/history')) {
|
|
131
|
+
const qReceiptId = event.queryStringParameters?.receiptId;
|
|
132
|
+
if (!qReceiptId) return errRespond(400, 'Missing receiptId for history fetch');
|
|
133
|
+
const queryRes = await ddbClient.send(new QueryCommand({
|
|
134
|
+
TableName: DDB_TABLE,
|
|
135
|
+
KeyConditionExpression: 'receiptId = :r',
|
|
136
|
+
ExpressionAttributeValues: { ':r': { S: qReceiptId } }
|
|
137
|
+
}));
|
|
138
|
+
const history = (queryRes.Items || []).map(i => ({
|
|
139
|
+
id: i.jobId?.S,
|
|
140
|
+
prompt: i.prompt?.S,
|
|
141
|
+
url: i.url?.S || '',
|
|
142
|
+
status: i.status?.S,
|
|
143
|
+
type: i.type?.S || 'video',
|
|
144
|
+
timestamp: i.timestamp?.S
|
|
145
|
+
})).sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
|
|
146
|
+
return respond(200, { history });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ── GET /status/<jobId> ─────────────────────────────────────────────
|
|
150
|
+
if (method === 'GET' && rawPath.includes('/status/')) {
|
|
151
|
+
const pathParts = rawPath.split('/status/');
|
|
152
|
+
const jobId = decodeURIComponent(pathParts[1] || (event.queryStringParameters?.jobId || body.jobId));
|
|
153
|
+
if (!jobId) return errRespond(400, 'Missing jobId in path or query');
|
|
154
|
+
console.log('[Poll] Checking ARN:', jobId);
|
|
155
|
+
let getResponse;
|
|
156
|
+
try { getResponse = await bedrockClient.send(new GetAsyncInvokeCommand({ invocationArn: jobId })); }
|
|
157
|
+
catch (e) { return errRespond(500, 'Failed to poll Bedrock status', e.message); }
|
|
158
|
+
const status = getResponse.status;
|
|
159
|
+
console.log('[Poll] Status:', status, '| Failure:', getResponse.failureMessage || 'none');
|
|
160
|
+
if (status === 'InProgress') return respond(202, { status: 'processing', message: 'Video still generating, poll again in 5s.' });
|
|
161
|
+
if (status === 'Failed') return errRespond(500, `Generation failed: ${getResponse.failureMessage || 'No detail'}`, JSON.stringify(getResponse));
|
|
162
|
+
const outputUri = getResponse.outputDataConfig?.s3OutputDataConfig?.s3Uri;
|
|
163
|
+
if (!outputUri) return errRespond(500, 'Bedrock completed but returned no S3 output URI', JSON.stringify(getResponse));
|
|
164
|
+
const s3Match = outputUri.match(/^s3:\/\/([^/]+)\/(.+)$/);
|
|
165
|
+
const bucket = s3Match ? s3Match[1] : S3_OUTPUT_BUCKET;
|
|
166
|
+
const prefix = (s3Match ? s3Match[2] : outputUri).replace(/\/+$/, '') + '/';
|
|
167
|
+
const listResp = await s3Client.send(new ListObjectsV2Command({ Bucket: bucket, Prefix: prefix }));
|
|
168
|
+
const mp4 = listResp.Contents?.find(i => i.Key.endsWith('.mp4'));
|
|
169
|
+
if (!mp4) return errRespond(500, `No .mp4 found in S3 output folder: ${prefix}`, JSON.stringify(listResp.Contents?.map(i => i.Key) || []));
|
|
170
|
+
const resultUrl = await getSignedUrl(s3Client, new GetObjectCommand({ Bucket: bucket, Key: mp4.Key }), { expiresIn: 86400 });
|
|
171
|
+
console.log('[Poll] Video ready:', resultUrl);
|
|
172
|
+
return respond(200, { status: 'success', url: resultUrl });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// ── POST: IMAGE generation ──────────────────────────────────────────
|
|
176
|
+
const prompt = body.prompt;
|
|
177
|
+
if (prompt) {
|
|
178
|
+
// Validate and consume the receipt BEFORE generating
|
|
179
|
+
const check = await consumeReceipt(receiptId);
|
|
180
|
+
if (!check.ok) return errRespond(402, check.reason);
|
|
181
|
+
|
|
182
|
+
let response;
|
|
183
|
+
try {
|
|
184
|
+
response = await bedrockClient.send(new InvokeModelCommand({
|
|
185
|
+
modelId: 'amazon.nova-canvas-v1:0',
|
|
186
|
+
contentType: 'application/json',
|
|
187
|
+
accept: 'application/json',
|
|
188
|
+
body: JSON.stringify({
|
|
189
|
+
taskType: "TEXT_IMAGE",
|
|
190
|
+
textToImageParams: { text: prompt },
|
|
191
|
+
imageGenerationConfig: { numberOfImages: 1, height: 1024, width: 1024, cfgScale: 8.0, quality: "premium" }
|
|
192
|
+
})
|
|
193
|
+
}));
|
|
194
|
+
} catch (e) {
|
|
195
|
+
const msg = e.message || String(e);
|
|
196
|
+
const lower = msg.toLowerCase();
|
|
197
|
+
if (lower.includes('throttling') || lower.includes('too many request') || lower.includes('quota')) {
|
|
198
|
+
console.log('[Nova Canvas] Throttled, falling back to Titan');
|
|
199
|
+
try {
|
|
200
|
+
response = await bedrockClient.send(new InvokeModelCommand({
|
|
201
|
+
modelId: 'amazon.titan-image-generator-v2:0',
|
|
202
|
+
contentType: 'application/json',
|
|
203
|
+
accept: 'application/json',
|
|
204
|
+
body: JSON.stringify({
|
|
205
|
+
taskType: "TEXT_IMAGE",
|
|
206
|
+
textToImageParams: { text: prompt },
|
|
207
|
+
imageGenerationConfig: { numberOfImages: 1, height: 1024, width: 1024, cfgScale: 8.0 }
|
|
208
|
+
})
|
|
209
|
+
}));
|
|
210
|
+
} catch (fallback) { return errRespond(429, 'Both Nova Canvas and Titan fallback throttled', fallback.message); }
|
|
211
|
+
} else if (msg.includes('AccessDenied') || msg.includes('not authorized')) { return errRespond(403, 'Bedrock access denied for image generation', msg); }
|
|
212
|
+
else { return errRespond(500, 'Image generation failed', msg); }
|
|
213
|
+
}
|
|
214
|
+
const rb = JSON.parse(new TextDecoder().decode(response.body));
|
|
215
|
+
if (!rb.images?.length) return errRespond(500, 'No images returned', JSON.stringify(rb));
|
|
216
|
+
const key = `nova-canvas-exports/image-${Date.now()}.png`;
|
|
217
|
+
await s3Client.send(new PutObjectCommand({ Bucket: S3_OUTPUT_BUCKET, Key: key, Body: Buffer.from(rb.images[0], 'base64'), ContentType: 'image/png' }));
|
|
218
|
+
const presignedUrl = await getSignedUrl(s3Client, new GetObjectCommand({ Bucket: S3_OUTPUT_BUCKET, Key: key }), { expiresIn: 86400 });
|
|
219
|
+
const jobId = `DONE:${encodeURIComponent(presignedUrl)}`;
|
|
220
|
+
try {
|
|
221
|
+
await ddbClient.send(new PutItemCommand({
|
|
222
|
+
TableName: DDB_TABLE,
|
|
223
|
+
Item: {
|
|
224
|
+
receiptId: { S: receiptId || 'teak' },
|
|
225
|
+
jobId: { S: jobId },
|
|
226
|
+
prompt: { S: prompt },
|
|
227
|
+
url: { S: presignedUrl },
|
|
228
|
+
status: { S: 'complete' },
|
|
229
|
+
type: { S: 'image' },
|
|
230
|
+
timestamp: { S: new Date().toISOString() }
|
|
231
|
+
}
|
|
232
|
+
}));
|
|
233
|
+
} catch (e) { console.error('[DynamoDB] Image log error:', e); }
|
|
234
|
+
return respond(200, { status: 'success', imageUrl: presignedUrl, jobId });
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ── POST: VIDEO generation ──────────────────────────────────────────
|
|
238
|
+
const masterPrompt = body.masterPrompt;
|
|
239
|
+
const referenceImage = body.referenceImage;
|
|
240
|
+
if (masterPrompt) {
|
|
241
|
+
// Validate and consume the receipt BEFORE generating
|
|
242
|
+
const check = await consumeReceipt(receiptId);
|
|
243
|
+
if (!check.ok) return errRespond(402, check.reason);
|
|
244
|
+
|
|
245
|
+
const reelInput = {
|
|
246
|
+
taskType: referenceImage ? "IMAGE_VIDEO" : "TEXT_VIDEO",
|
|
247
|
+
textToVideoParams: { text: masterPrompt },
|
|
248
|
+
videoGenerationConfig: { durationSeconds: 6, fps: 24, dimension: "1280x720" }
|
|
249
|
+
};
|
|
250
|
+
if (referenceImage) {
|
|
251
|
+
reelInput.imageToVideoParams = { images: [{ format: "jpeg", source: { bytes: referenceImage.split(',')[1] } }] };
|
|
252
|
+
}
|
|
253
|
+
let startResp;
|
|
254
|
+
try {
|
|
255
|
+
startResp = await bedrockClient.send(new StartAsyncInvokeCommand({
|
|
256
|
+
modelId: 'amazon.nova-reel-v1:1',
|
|
257
|
+
clientRequestToken: `jk-reel-${Date.now()}`,
|
|
258
|
+
outputDataConfig: { s3OutputDataConfig: { s3Uri: `s3://${S3_OUTPUT_BUCKET}/nova-reel-exports/` } },
|
|
259
|
+
modelInput: reelInput
|
|
260
|
+
}));
|
|
261
|
+
} catch (e) {
|
|
262
|
+
const msg = e.message || String(e);
|
|
263
|
+
const lower = msg.toLowerCase();
|
|
264
|
+
if (lower.includes('throttlingexception') || lower.includes('too many request')) {
|
|
265
|
+
console.log('[Nova Reel] Throttled, falling back to Luma Ray');
|
|
266
|
+
const lumaClient = new BedrockRuntimeClient({ region: 'us-west-2' });
|
|
267
|
+
try {
|
|
268
|
+
startResp = await lumaClient.send(new StartAsyncInvokeCommand({
|
|
269
|
+
modelId: 'luma.ray-v2:0',
|
|
270
|
+
clientRequestToken: `jk-luma-${Date.now()}`,
|
|
271
|
+
outputDataConfig: { s3OutputDataConfig: { s3Uri: `s3://${S3_OUTPUT_BUCKET}/luma-exports/` } },
|
|
272
|
+
modelInput: { prompt: masterPrompt, aspect_ratio: "16:9", resolution: "720p" }
|
|
273
|
+
}));
|
|
274
|
+
} catch (fallback) { return errRespond(429, 'Both Nova Reel and Luma fallback throttled', fallback.message); }
|
|
275
|
+
} else if (msg.includes('AccessDenied') || msg.includes('not authorized')) { return errRespond(403, 'Bedrock access denied for video generation', msg); }
|
|
276
|
+
else if (msg.includes('ValidationException')) { return errRespond(400, 'Invalid video parameters', msg); }
|
|
277
|
+
else { return errRespond(500, 'Video generation start failed', msg); }
|
|
278
|
+
}
|
|
279
|
+
const jobId = startResp.invocationArn || `unknown-${Date.now()}`;
|
|
280
|
+
try {
|
|
281
|
+
await ddbClient.send(new PutItemCommand({
|
|
282
|
+
TableName: DDB_TABLE,
|
|
283
|
+
Item: {
|
|
284
|
+
receiptId: { S: receiptId || 'teak' },
|
|
285
|
+
jobId: { S: jobId },
|
|
286
|
+
prompt: { S: masterPrompt },
|
|
287
|
+
url: { S: '' },
|
|
288
|
+
status: { S: 'pending' },
|
|
289
|
+
type: { S: 'video' },
|
|
290
|
+
timestamp: { S: new Date().toISOString() }
|
|
291
|
+
}
|
|
292
|
+
}));
|
|
293
|
+
} catch (e) { console.error('[DynamoDB] Video start log error:', e); }
|
|
294
|
+
return respond(202, { status: 'started', jobId, message: 'Video generation started. Poll /status/<jobId>.' });
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return errRespond(400, 'No valid prompt supplied');
|
|
298
|
+
} catch (err) {
|
|
299
|
+
return errRespond(500, 'Unhandled Lambda error', err.message);
|
|
300
|
+
}
|
|
301
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const archiver = require('archiver');
|
|
4
|
+
|
|
5
|
+
const zipPath = path.join(__dirname, 'worker_deploy.zip');
|
|
6
|
+
const sourceFile = path.join(__dirname, 'worker_code', 'index.js');
|
|
7
|
+
|
|
8
|
+
const output = fs.createWriteStream(zipPath);
|
|
9
|
+
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
10
|
+
|
|
11
|
+
output.on('close', () => {
|
|
12
|
+
console.log(`Successfully created worker_deploy.zip: ${archive.pointer()} total bytes`);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
archive.on('error', (err) => {
|
|
16
|
+
console.error('Error zipping:', err);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
archive.pipe(output);
|
|
20
|
+
archive.file(sourceFile, { name: 'index.js' });
|
|
21
|
+
archive.finalize();
|
package/clean_page.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = './web-hub/src/app/page.tsx';
|
|
3
|
+
|
|
4
|
+
let code = fs.readFileSync(path, 'utf8');
|
|
5
|
+
|
|
6
|
+
// 1. Remove the entire Trial Timers useEffect block
|
|
7
|
+
const trialTimerStartRegex = /\/\/ == Trial Timers ==\s*useEffect\(\(\) => \{/m;
|
|
8
|
+
const match = code.match(trialTimerStartRegex);
|
|
9
|
+
if (match) {
|
|
10
|
+
const startIndex = match.index;
|
|
11
|
+
let openBraces = 0;
|
|
12
|
+
let endIndex = -1;
|
|
13
|
+
let started = false;
|
|
14
|
+
for (let i = startIndex; i < code.length; i++) {
|
|
15
|
+
if (code[i] === '{') {
|
|
16
|
+
openBraces++;
|
|
17
|
+
started = true;
|
|
18
|
+
} else if (code[i] === '}') {
|
|
19
|
+
openBraces--;
|
|
20
|
+
if (started && openBraces === 0) {
|
|
21
|
+
// Check if the next characters are "}, [trialActive, trialTimeLeft, diamonizeTrialActive, diamonizeTimeLeft]);"
|
|
22
|
+
const searchEnd = code.indexOf(';', i);
|
|
23
|
+
endIndex = searchEnd + 1;
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (endIndex !== -1) {
|
|
29
|
+
code = code.substring(0, startIndex) + code.substring(endIndex);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 2. Remove any other leftover references to trial variables (this might require manual regex for JSX buttons)
|
|
34
|
+
code = code.replace(/\{\s*!maxionTrialConsumed\s*&&\s*\([\s\S]*?<button[\s\S]*?START 1-HOUR FREE TRIAL[\s\S]*?<\/button>\s*\)\s*\}/gm, '');
|
|
35
|
+
code = code.replace(/\{\s*!diamonizeTrialConsumed\s*&&\s*\([\s\S]*?<button[\s\S]*?START 1-HOUR FREE TRIAL[\s\S]*?<\/button>\s*\)\s*\}/gm, '');
|
|
36
|
+
|
|
37
|
+
// Global Maxion Timer HUD
|
|
38
|
+
code = code.replace(/\{\s*trialActive\s*&&\s*\([\s\S]*?MAXION GOVERNOR \[ACTIVE\][\s\S]*?<\/div>\s*\)\s*\}/gm, '');
|
|
39
|
+
|
|
40
|
+
// Global Diamonize Timer HUD
|
|
41
|
+
code = code.replace(/\{\s*diamonizeTrialActive\s*&&\s*\([\s\S]*?DIAMONIZE TUNNEL \[ACTIVE\][\s\S]*?<\/svg>\s*\)\s*\}/gm, '');
|
|
42
|
+
|
|
43
|
+
// Global Trial Indicator
|
|
44
|
+
code = code.replace(/\{\s*\/\* Global Trial Indicator \*\/\s*\}/gm, '');
|
|
45
|
+
code = code.replace(/\{\s*trialActive\s*&&\s*appState\s*!==\s*'maxion_sandbox'\s*&&\s*\([\s\S]*?MAXION GOVERNOR ACTIVE[\s\S]*?<\/div>\s*\)\s*\}/gm, '');
|
|
46
|
+
|
|
47
|
+
// Fix 'DISABLE MAXION' button which uses setTrialActive and setTrialTimeLeft
|
|
48
|
+
code = code.replace(/setTrialActive\(false\);\s*/gm, '');
|
|
49
|
+
code = code.replace(/setTrialTimeLeft\(3600\);\s*/gm, '');
|
|
50
|
+
|
|
51
|
+
// Also clean up any other syntax issues that might arise.
|
|
52
|
+
fs.writeFileSync(path, code, 'utf8');
|
|
53
|
+
console.log('Cleanup script finished.');
|
package/clean_page_2.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = './web-hub/src/app/page.tsx';
|
|
3
|
+
|
|
4
|
+
let code = fs.readFileSync(path, 'utf8');
|
|
5
|
+
|
|
6
|
+
// The simplest way to clear all this out safely without AST parsing
|
|
7
|
+
// is to replace the TS error lines with empty strings or false where appropriate.
|
|
8
|
+
|
|
9
|
+
// Remove the entire useEffect block for Trial Timers
|
|
10
|
+
code = code.replace(/\/\/ == Trial Timers ==[\s\S]*?\}, \[trialActive, trialTimeLeft, diamonizeTrialActive, diamonizeTimeLeft\]\);/gm, '');
|
|
11
|
+
|
|
12
|
+
// Clean up remaining TS errors identified in the log
|
|
13
|
+
code = code.replace(/\{\s*!diamonizeTrialConsumed\s*&&\s*\([\s\S]*?<button[\s\S]*?START 1-HOUR FREE TRIAL[\s\S]*?<\/button>\s*\)\s*\}/gm, '');
|
|
14
|
+
code = code.replace(/\{\s*!maxionTrialConsumed\s*&&\s*\([\s\S]*?<button[\s\S]*?START 1-HOUR FREE TRIAL[\s\S]*?<\/button>\s*\)\s*\}/gm, '');
|
|
15
|
+
|
|
16
|
+
// The Global Maxion Timer HUD
|
|
17
|
+
code = code.replace(/\{\s*trialActive\s*&&\s*\(\s*<div style=\{\{\s*position: 'fixed'[\s\S]*?MAXION GOVERNOR \[ACTIVE\][\s\S]*?<\/div>\s*\)\s*\}/gm, '');
|
|
18
|
+
|
|
19
|
+
// The Global Diamonize Timer HUD
|
|
20
|
+
code = code.replace(/\{\s*diamonizeTrialActive\s*&&\s*\(\s*<div style=\{\{\s*position: 'fixed'[\s\S]*?DIAMONIZE TUNNEL \[ACTIVE\][\s\S]*?<\/div>\s*\)\s*\}/gm, '');
|
|
21
|
+
|
|
22
|
+
// Global Trial Indicator
|
|
23
|
+
code = code.replace(/\{\s*\/\* Global Trial Indicator \*\/\s*\}/gm, '');
|
|
24
|
+
code = code.replace(/\{\s*trialActive\s*&&\s*appState\s*!==\s*'maxion_sandbox'\s*&&\s*\(\s*<div style=\{\{\s*position: 'fixed'[\s\S]*?MAXION GOVERNOR ACTIVE[\s\S]*?<\/div>\s*\)\s*\}/gm, '');
|
|
25
|
+
|
|
26
|
+
// Replace any leftover references inside conditionals
|
|
27
|
+
code = code.replace(/\(diamonizeTrialActive \|\| diamonizeAccess\)/g, '(diamonizeAccess)');
|
|
28
|
+
code = code.replace(/\(trialActive \|\| maxionAccess\)/g, '(maxionAccess)');
|
|
29
|
+
code = code.replace(/!diamonizeTrialActive/g, 'false');
|
|
30
|
+
code = code.replace(/!trialActive/g, 'false');
|
|
31
|
+
|
|
32
|
+
// Fix 'DISABLE MAXION' button block which might have been missed
|
|
33
|
+
code = code.replace(/setTrialActive\(false\);\s*/gm, '');
|
|
34
|
+
code = code.replace(/setTrialTimeLeft\(3600\);\s*/gm, '');
|
|
35
|
+
|
|
36
|
+
fs.writeFileSync(path, code, 'utf8');
|
|
37
|
+
console.log('Second cleanup script finished.');
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = './web-hub/src/app/page.tsx';
|
|
3
|
+
let code = fs.readFileSync(path, 'utf8');
|
|
4
|
+
|
|
5
|
+
// 1. Remove Quezar & Diamonize bypasses
|
|
6
|
+
code = code.replace(/setTimeout\(\(\) => setQuezarAccess\(true\), 5000\);/g, '');
|
|
7
|
+
code = code.replace(/setTimeout\(\(\) => setDiamonizeAccess\(true\), 5000\);/g, '');
|
|
8
|
+
|
|
9
|
+
// 2. We will leave the trialActive and other state variables intact, but we will strip the actual UI elements so users can never click them.
|
|
10
|
+
// This is much safer than stripping the React State which causes 35+ TS errors.
|
|
11
|
+
|
|
12
|
+
// Maxion Trial Button
|
|
13
|
+
code = code.replace(/\{\s*!maxionTrialConsumed\s*&&\s*\([\s\S]*?<button[\s\S]*?START 1-HOUR FREE TRIAL[\s\S]*?<\/button>\s*\)\s*\}/gm, '');
|
|
14
|
+
|
|
15
|
+
// Diamonize Trial Button
|
|
16
|
+
code = code.replace(/\{\s*!diamonizeTrialConsumed\s*&&\s*\([\s\S]*?<button[\s\S]*?START 1-HOUR FREE TRIAL[\s\S]*?<\/button>\s*\)\s*\}/gm, '');
|
|
17
|
+
|
|
18
|
+
// Global Maxion Timer HUD
|
|
19
|
+
code = code.replace(/\{\s*trialActive\s*&&\s*\(\s*<div style=\{\{\s*position: 'fixed'[\s\S]*?MAXION GOVERNOR \[ACTIVE\][\s\S]*?<\/div>\s*\)\s*\}/gm, '');
|
|
20
|
+
|
|
21
|
+
// Global Diamonize Timer HUD
|
|
22
|
+
code = code.replace(/\{\s*diamonizeTrialActive\s*&&\s*\(\s*<div style=\{\{\s*position: 'fixed'[\s\S]*?DIAMONIZE TUNNEL \[ACTIVE\][\s\S]*?<\/div>\s*\)\s*\}/gm, '');
|
|
23
|
+
|
|
24
|
+
// Global Trial Indicator
|
|
25
|
+
code = code.replace(/\{\s*\/\* Global Trial Indicator \*\/\s*\}/gm, '');
|
|
26
|
+
code = code.replace(/\{\s*trialActive\s*&&\s*appState\s*!==\s*'maxion_sandbox'\s*&&\s*\(\s*<div style=\{\{\s*position: 'fixed'[\s\S]*?MAXION GOVERNOR ACTIVE[\s\S]*?<\/div>\s*\)\s*\}/gm, '');
|
|
27
|
+
|
|
28
|
+
// Stop the timers from doing anything malicious or popping up toasts
|
|
29
|
+
code = code.replace(/showToast\('error', '\[TRIAL EXPIRED\] MAXION HARDWARE ACCESS REVOKED'\);/g, '');
|
|
30
|
+
code = code.replace(/showToast\('error', '\[TRIAL EXPIRED\] DIAMONIZE SECURE TUNNEL COLLAPSED'\);/g, '');
|
|
31
|
+
code = code.replace(/setTrialActive\(false\);/g, '');
|
|
32
|
+
code = code.replace(/setDiamonizeTrialActive\(false\);/g, '');
|
|
33
|
+
|
|
34
|
+
fs.writeFileSync(path, code, 'utf8');
|
|
35
|
+
console.log('Safe trial cleanup finished.');
|
package/configure_aws.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
require('dotenv').config();
|
|
2
|
+
const { S3Client, PutBucketCorsCommand, PutBucketOwnershipControlsCommand } = require("@aws-sdk/client-s3");
|
|
3
|
+
const { LambdaClient, UpdateFunctionCodeCommand } = require("@aws-sdk/client-lambda");
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const archiver = require('archiver');
|
|
7
|
+
|
|
8
|
+
const region = "us-east-1";
|
|
9
|
+
const creds = {
|
|
10
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
11
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const s3 = new S3Client({ region, credentials: creds });
|
|
15
|
+
const lambda = new LambdaClient({ region, credentials: creds });
|
|
16
|
+
|
|
17
|
+
const BUCKET_NAME = process.env.S3_OUTPUT_BUCKET || 'jk-advanced-tech-web-videos';
|
|
18
|
+
|
|
19
|
+
async function configureS3() {
|
|
20
|
+
try {
|
|
21
|
+
console.log(`Configuring CORS for bucket: ${BUCKET_NAME}`);
|
|
22
|
+
await s3.send(new PutBucketCorsCommand({
|
|
23
|
+
Bucket: BUCKET_NAME,
|
|
24
|
+
CORSConfiguration: {
|
|
25
|
+
CORSRules: [
|
|
26
|
+
{
|
|
27
|
+
AllowedHeaders: ["*"],
|
|
28
|
+
AllowedMethods: ["GET", "PUT", "HEAD"],
|
|
29
|
+
AllowedOrigins: ["*"],
|
|
30
|
+
ExposeHeaders: ["ETag"]
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}));
|
|
35
|
+
console.log("CORS configuration applied successfully.");
|
|
36
|
+
|
|
37
|
+
console.log(`Configuring Object Ownership for bucket: ${BUCKET_NAME}`);
|
|
38
|
+
await s3.send(new PutBucketOwnershipControlsCommand({
|
|
39
|
+
Bucket: BUCKET_NAME,
|
|
40
|
+
OwnershipControls: {
|
|
41
|
+
Rules: [
|
|
42
|
+
{
|
|
43
|
+
ObjectOwnership: "BucketOwnerEnforced"
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
}));
|
|
48
|
+
console.log("Object Ownership applied successfully.");
|
|
49
|
+
} catch (e) {
|
|
50
|
+
console.error("Failed to configure S3:", e.message);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function packageAndDeployLambda() {
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
const zipPath = path.join(__dirname, 'lambda.zip');
|
|
57
|
+
const output = fs.createWriteStream(zipPath);
|
|
58
|
+
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
59
|
+
|
|
60
|
+
output.on('close', async () => {
|
|
61
|
+
console.log(`Created zip archive (${archive.pointer()} total bytes)`);
|
|
62
|
+
try {
|
|
63
|
+
// Read the zip file
|
|
64
|
+
const zipBuffer = fs.readFileSync(zipPath);
|
|
65
|
+
|
|
66
|
+
// Assuming the lambda function name is related to the project
|
|
67
|
+
// In production, you'd get this from Terraform/CDK or specify it.
|
|
68
|
+
// For now, let's just attempt a common name like `nova-canvas-reel-handler` or we can skip deploy if we don't know the name.
|
|
69
|
+
// Let's actually check what lambdas exist or ask the user.
|
|
70
|
+
resolve(zipPath);
|
|
71
|
+
} catch (err) {
|
|
72
|
+
reject(err);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
archive.on('error', (err) => { reject(err); });
|
|
77
|
+
archive.pipe(output);
|
|
78
|
+
|
|
79
|
+
// Append the handler
|
|
80
|
+
archive.file('aws_lambda_handler.js', { name: 'index.js' }); // The AWS lambda runtime often expects index.js by default
|
|
81
|
+
|
|
82
|
+
// We also need node_modules if we use @aws-sdk/s3-request-presigner
|
|
83
|
+
// Let's add them
|
|
84
|
+
archive.directory('node_modules/@aws-sdk', 'node_modules/@aws-sdk');
|
|
85
|
+
archive.directory('node_modules/@aws-crypto', 'node_modules/@aws-crypto');
|
|
86
|
+
archive.directory('node_modules/@smithy', 'node_modules/@smithy');
|
|
87
|
+
archive.directory('node_modules/fast-xml-parser', 'node_modules/fast-xml-parser');
|
|
88
|
+
archive.directory('node_modules/strnum', 'node_modules/strnum');
|
|
89
|
+
archive.directory('node_modules/tslib', 'node_modules/tslib');
|
|
90
|
+
archive.directory('node_modules/uuid', 'node_modules/uuid');
|
|
91
|
+
|
|
92
|
+
archive.finalize();
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function run() {
|
|
97
|
+
await configureS3();
|
|
98
|
+
await packageAndDeployLambda();
|
|
99
|
+
console.log("Configuration run complete.");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
run();
|
package/cors.json
ADDED
package/create_lambda.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require('dotenv').config();
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const { LambdaClient, CreateFunctionCommand } = require('@aws-sdk/client-lambda');
|
|
4
|
+
const { IAMClient, CreateRoleCommand, AttachRolePolicyCommand, GetRoleCommand } = require('@aws-sdk/client-iam');
|
|
5
|
+
|
|
6
|
+
const awsConfig = {
|
|
7
|
+
region: 'us-east-1',
|
|
8
|
+
credentials: {
|
|
9
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
10
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const lambdaClient = new LambdaClient(awsConfig);
|
|
15
|
+
const iamClient = new IAMClient(awsConfig);
|
|
16
|
+
const FUNCTION_NAME = 'lineage_api';
|
|
17
|
+
const ROLE_NAME = 'LineageApiLambdaExecutionRole';
|
|
18
|
+
|
|
19
|
+
async function sleep(ms) {
|
|
20
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function getOrCreateRole() {
|
|
24
|
+
let roleArn;
|
|
25
|
+
try {
|
|
26
|
+
const roleRes = await iamClient.send(new GetRoleCommand({ RoleName: ROLE_NAME }));
|
|
27
|
+
roleArn = roleRes.Role.Arn;
|
|
28
|
+
console.log(`✅ IAM Role already exists: ${roleArn}`);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error.name === 'NoSuchEntityException') {
|
|
31
|
+
console.log(`Creating IAM Role: ${ROLE_NAME}...`);
|
|
32
|
+
const assumeRolePolicy = JSON.stringify({
|
|
33
|
+
Version: "2012-10-17",
|
|
34
|
+
Statement: [{
|
|
35
|
+
Action: "sts:AssumeRole",
|
|
36
|
+
Principal: { Service: "lambda.amazonaws.com" },
|
|
37
|
+
Effect: "Allow",
|
|
38
|
+
}]
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const createRes = await iamClient.send(new CreateRoleCommand({
|
|
42
|
+
RoleName: ROLE_NAME,
|
|
43
|
+
AssumeRolePolicyDocument: assumeRolePolicy
|
|
44
|
+
}));
|
|
45
|
+
roleArn = createRes.Role.Arn;
|
|
46
|
+
console.log(`✅ Created IAM Role: ${roleArn}`);
|
|
47
|
+
|
|
48
|
+
console.log(`Attaching basic execution policy...`);
|
|
49
|
+
await iamClient.send(new AttachRolePolicyCommand({
|
|
50
|
+
RoleName: ROLE_NAME,
|
|
51
|
+
PolicyArn: 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
console.log(`Waiting 15 seconds for IAM role to propagate...`);
|
|
55
|
+
await sleep(15000);
|
|
56
|
+
} else {
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return roleArn;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function createLambda() {
|
|
64
|
+
try {
|
|
65
|
+
const roleArn = await getOrCreateRole();
|
|
66
|
+
|
|
67
|
+
console.log(`Attempting to create Lambda function: ${FUNCTION_NAME}...`);
|
|
68
|
+
const zipBuffer = fs.readFileSync('C:\\Users\\aruuh\\.gemini\\antigravity\\scratch\\Maxion_Cool_Breeze\\aws-lambda-stripe\\lineage_api.zip');
|
|
69
|
+
|
|
70
|
+
const createCommand = new CreateFunctionCommand({
|
|
71
|
+
FunctionName: FUNCTION_NAME,
|
|
72
|
+
Runtime: 'nodejs20.x',
|
|
73
|
+
Role: roleArn,
|
|
74
|
+
Handler: 'lineage_api.handler',
|
|
75
|
+
Code: { ZipFile: zipBuffer }
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const result = await lambdaClient.send(createCommand);
|
|
79
|
+
console.log(`🚀 Successfully created ${FUNCTION_NAME}. ARN: ${result.FunctionArn}`);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error(`❌ Failed to create Lambda:`, error.message);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
createLambda();
|