securenow 7.6.6 → 7.6.8
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/NPM_README.md +13 -13
- package/README.md +21 -37
- package/app-config.js +5 -3
- package/cli/config.js +4 -3
- package/cli/diagnostics.js +54 -15
- package/cli/run.js +40 -11
- package/firewall-only.js +1 -1
- package/firewall.js +88 -57
- package/mcp/catalog.js +1 -1
- package/nextjs-webpack-config.js +3 -15
- package/nextjs.js +21 -23
- package/nuxt-server-plugin.mjs +20 -10
- package/package.json +33 -34
- package/register.js +1 -1
- package/tracing.js +17 -7
- package/web-vite.mjs +23 -13
- package/CONSUMING-APPS-GUIDE.md +0 -463
- package/docs/ALL-FRAMEWORKS-QUICKSTART.md +0 -1388
- package/docs/API-KEYS-GUIDE.md +0 -278
- package/docs/ARCHITECTURE.md +0 -408
- package/docs/AUTO-BODY-CAPTURE.md +0 -412
- package/docs/AUTO-SETUP-SUMMARY.md +0 -331
- package/docs/AUTO-SETUP.md +0 -419
- package/docs/AUTOMATIC-IP-CAPTURE.md +0 -359
- package/docs/BODY-CAPTURE-FIX.md +0 -261
- package/docs/BODY-CAPTURE-QUICKSTART.md +0 -147
- package/docs/CHANGELOG-NEXTJS.md +0 -235
- package/docs/COMPLETION-REPORT.md +0 -408
- package/docs/CUSTOMER-GUIDE.md +0 -364
- package/docs/EASIEST-SETUP.md +0 -342
- package/docs/ENVIRONMENT-VARIABLES.md +0 -166
- package/docs/ENVIRONMENTS.md +0 -60
- package/docs/EXPRESS-BODY-CAPTURE.md +0 -1028
- package/docs/EXPRESS-SETUP-GUIDE.md +0 -722
- package/docs/FINAL-SOLUTION.md +0 -335
- package/docs/FIREWALL-GUIDE.md +0 -440
- package/docs/IMPLEMENTATION-SUMMARY.md +0 -410
- package/docs/INDEX.md +0 -222
- package/docs/LOGGING-GUIDE.md +0 -704
- package/docs/LOGGING-QUICKSTART.md +0 -221
- package/docs/MCP-GUIDE.md +0 -58
- package/docs/NEXTJS-BODY-CAPTURE-COMPARISON.md +0 -323
- package/docs/NEXTJS-BODY-CAPTURE.md +0 -368
- package/docs/NEXTJS-GUIDE.md +0 -392
- package/docs/NEXTJS-QUICKSTART.md +0 -83
- package/docs/NEXTJS-SETUP-COMPLETE.md +0 -795
- package/docs/NEXTJS-WEBPACK-WARNINGS.md +0 -267
- package/docs/NEXTJS-WRAPPER-APPROACH.md +0 -414
- package/docs/NUXT-GUIDE.md +0 -173
- package/docs/QUICKSTART-BODY-CAPTURE.md +0 -293
- package/docs/REDACTION-EXAMPLES.md +0 -484
- package/docs/REQUEST-BODY-CAPTURE.md +0 -587
- package/docs/SOLUTION-SUMMARY.md +0 -312
- package/docs/VERCEL-OTEL-MIGRATION.md +0 -255
- package/examples/README.md +0 -265
- package/examples/express-with-logging.js +0 -137
- package/examples/instrumentation-with-auto-capture.ts +0 -41
- package/examples/next.config.js +0 -37
- package/examples/nextjs-api-route-with-body-capture.ts +0 -54
- package/examples/nextjs-env-example.txt +0 -32
- package/examples/nextjs-instrumentation.js +0 -36
- package/examples/nextjs-instrumentation.ts +0 -36
- package/examples/nextjs-middleware.js +0 -37
- package/examples/nextjs-middleware.ts +0 -37
- package/examples/nextjs-with-logging-example.md +0 -301
- package/examples/nextjs-with-options.ts +0 -36
- package/examples/test-nextjs-setup.js +0 -70
- package/postinstall.js +0 -296
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Next.js Middleware with SecureNow Body Capture
|
|
3
|
-
*
|
|
4
|
-
* Place this file as: middleware.ts (in your project root or src/)
|
|
5
|
-
*
|
|
6
|
-
* This single line enables automatic body capture for all API routes!
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
// Just export the middleware from securenow - that's it!
|
|
10
|
-
export { middleware } from 'securenow/nextjs-middleware';
|
|
11
|
-
|
|
12
|
-
// Optional: Configure which routes to apply to
|
|
13
|
-
export const config = {
|
|
14
|
-
matcher: '/api/:path*', // Apply to all API routes
|
|
15
|
-
|
|
16
|
-
// Or be more specific:
|
|
17
|
-
// matcher: ['/api/login', '/api/register', '/api/graphql'],
|
|
18
|
-
|
|
19
|
-
// Or apply to everything:
|
|
20
|
-
// matcher: '/((?!_next/static|_next/image|favicon.ico).*)',
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* That's it! Request bodies are now automatically captured with:
|
|
25
|
-
* - Sensitive fields redacted (passwords, tokens, cards, etc.)
|
|
26
|
-
* - Size limits enforced
|
|
27
|
-
* - All content types supported (JSON, GraphQL, Form)
|
|
28
|
-
* - Zero impact on request processing
|
|
29
|
-
*
|
|
30
|
-
* Configure via environment variables:
|
|
31
|
-
* SECURENOW_MAX_BODY_SIZE=20480
|
|
32
|
-
* SECURENOW_SENSITIVE_FIELDS=email,phone,address
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
# Next.js with Logging Example
|
|
2
|
-
|
|
3
|
-
This example shows how to set up logging in a Next.js application.
|
|
4
|
-
|
|
5
|
-
## Setup
|
|
6
|
-
|
|
7
|
-
### 1. Install SecureNow
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install securenow
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
### 2. Create `instrumentation.ts`
|
|
14
|
-
|
|
15
|
-
Create `instrumentation.ts` in your project root (same level as `app/` or `pages/`):
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
// instrumentation.ts
|
|
19
|
-
export async function register() {
|
|
20
|
-
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
21
|
-
// Enable logging
|
|
22
|
-
process.env.SECURENOW_LOGGING_ENABLED = '1';
|
|
23
|
-
|
|
24
|
-
// Initialize tracing and logging
|
|
25
|
-
await import('securenow/register');
|
|
26
|
-
await import('securenow/console-instrumentation');
|
|
27
|
-
|
|
28
|
-
console.log('SecureNow initialized with logging enabled');
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### 3. Configure Environment Variables
|
|
34
|
-
|
|
35
|
-
Create `.env.local`:
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
SECURENOW_LOGGING_ENABLED=1
|
|
39
|
-
SECURENOW_APPID=my-nextjs-app
|
|
40
|
-
SECURENOW_INSTANCE=http://localhost:4318
|
|
41
|
-
|
|
42
|
-
# For SecureNow or managed OTLP (example):
|
|
43
|
-
# SECURENOW_INSTANCE=https://ingest.<region>.securenow.ai:443
|
|
44
|
-
# OTEL_EXPORTER_OTLP_HEADERS="x-api-key=<your-key>"
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### 4. Enable Instrumentation in `next.config.js`
|
|
48
|
-
|
|
49
|
-
```javascript
|
|
50
|
-
// next.config.js
|
|
51
|
-
/** @type {import('next').NextConfig} */
|
|
52
|
-
const nextConfig = {
|
|
53
|
-
experimental: {
|
|
54
|
-
instrumentationHook: true,
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
module.exports = nextConfig;
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Usage Examples
|
|
62
|
-
|
|
63
|
-
### API Route with Logging
|
|
64
|
-
|
|
65
|
-
```typescript
|
|
66
|
-
// app/api/users/route.ts
|
|
67
|
-
import { NextRequest, NextResponse } from 'next/server';
|
|
68
|
-
|
|
69
|
-
export async function GET(request: NextRequest) {
|
|
70
|
-
console.log('GET /api/users called', {
|
|
71
|
-
searchParams: Object.fromEntries(request.nextUrl.searchParams),
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
// Fetch users from database
|
|
76
|
-
const users = await fetchUsers();
|
|
77
|
-
|
|
78
|
-
console.info('Users fetched successfully', {
|
|
79
|
-
count: users.length,
|
|
80
|
-
timestamp: new Date().toISOString(),
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
return NextResponse.json(users);
|
|
84
|
-
} catch (error) {
|
|
85
|
-
console.error('Failed to fetch users', {
|
|
86
|
-
error: error.message,
|
|
87
|
-
stack: error.stack,
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
return NextResponse.json(
|
|
91
|
-
{ error: 'Failed to fetch users' },
|
|
92
|
-
{ status: 500 }
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export async function POST(request: NextRequest) {
|
|
98
|
-
const body = await request.json();
|
|
99
|
-
|
|
100
|
-
console.info('Creating new user', {
|
|
101
|
-
email: body.email,
|
|
102
|
-
name: body.name,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
const user = await createUser(body);
|
|
107
|
-
|
|
108
|
-
console.log('User created successfully', {
|
|
109
|
-
userId: user.id,
|
|
110
|
-
email: user.email,
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
return NextResponse.json(user, { status: 201 });
|
|
114
|
-
} catch (error) {
|
|
115
|
-
console.error('Failed to create user', {
|
|
116
|
-
error: error.message,
|
|
117
|
-
body,
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
return NextResponse.json(
|
|
121
|
-
{ error: 'Failed to create user' },
|
|
122
|
-
{ status: 500 }
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Server Component with Logging
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
// app/dashboard/page.tsx
|
|
132
|
-
export default async function DashboardPage() {
|
|
133
|
-
console.log('Dashboard page rendering started');
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
const data = await fetchDashboardData();
|
|
137
|
-
|
|
138
|
-
console.info('Dashboard data loaded', {
|
|
139
|
-
itemCount: data.items.length,
|
|
140
|
-
loadTime: Date.now(),
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
return (
|
|
144
|
-
<div>
|
|
145
|
-
<h1>Dashboard</h1>
|
|
146
|
-
{/* Render your dashboard */}
|
|
147
|
-
</div>
|
|
148
|
-
);
|
|
149
|
-
} catch (error) {
|
|
150
|
-
console.error('Dashboard data fetch failed', {
|
|
151
|
-
error: error.message,
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
return <div>Error loading dashboard</div>;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
### Server Action with Logging
|
|
160
|
-
|
|
161
|
-
```typescript
|
|
162
|
-
// app/actions.ts
|
|
163
|
-
'use server';
|
|
164
|
-
|
|
165
|
-
export async function submitForm(formData: FormData) {
|
|
166
|
-
const name = formData.get('name');
|
|
167
|
-
const email = formData.get('email');
|
|
168
|
-
|
|
169
|
-
console.info('Form submission received', {
|
|
170
|
-
name,
|
|
171
|
-
email,
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
try {
|
|
175
|
-
const result = await saveToDatabase({ name, email });
|
|
176
|
-
|
|
177
|
-
console.log('Form saved successfully', {
|
|
178
|
-
resultId: result.id,
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
return { success: true, id: result.id };
|
|
182
|
-
} catch (error) {
|
|
183
|
-
console.error('Form submission failed', {
|
|
184
|
-
error: error.message,
|
|
185
|
-
formData: { name, email },
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
return { success: false, error: error.message };
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### Middleware with Logging
|
|
194
|
-
|
|
195
|
-
```typescript
|
|
196
|
-
// middleware.ts
|
|
197
|
-
import { NextResponse } from 'next/server';
|
|
198
|
-
import type { NextRequest } from 'next/server';
|
|
199
|
-
|
|
200
|
-
export function middleware(request: NextRequest) {
|
|
201
|
-
console.log('Middleware executed', {
|
|
202
|
-
path: request.nextUrl.pathname,
|
|
203
|
-
method: request.method,
|
|
204
|
-
userAgent: request.headers.get('user-agent'),
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
// Authentication check example
|
|
208
|
-
const token = request.cookies.get('auth-token');
|
|
209
|
-
|
|
210
|
-
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
|
|
211
|
-
console.warn('Unauthorized access attempt', {
|
|
212
|
-
path: request.nextUrl.pathname,
|
|
213
|
-
ip: request.ip,
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
return NextResponse.redirect(new URL('/login', request.url));
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return NextResponse.next();
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
export const config = {
|
|
223
|
-
matcher: ['/dashboard/:path*', '/api/:path*'],
|
|
224
|
-
};
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
## Run the Application
|
|
228
|
-
|
|
229
|
-
```bash
|
|
230
|
-
npm run dev
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
You should see in the console:
|
|
234
|
-
|
|
235
|
-
```
|
|
236
|
-
[securenow] OTel SDK started → http://localhost:4318/v1/traces
|
|
237
|
-
[securenow] 📋 Logging: ENABLED → http://localhost:4318/v1/logs
|
|
238
|
-
[securenow] Console instrumentation installed
|
|
239
|
-
SecureNow initialized with logging enabled
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
## View Logs in SecureNow
|
|
243
|
-
|
|
244
|
-
1. Open your SecureNow dashboard
|
|
245
|
-
2. Navigate to **Logs** section
|
|
246
|
-
3. Filter by `service.name = my-nextjs-app`
|
|
247
|
-
4. See all your application logs with:
|
|
248
|
-
- Automatic severity levels
|
|
249
|
-
- Structured attributes
|
|
250
|
-
- Trace correlation (when logs happen during traced requests)
|
|
251
|
-
|
|
252
|
-
## Advanced: Direct Logger API
|
|
253
|
-
|
|
254
|
-
For more control, use the logger API directly:
|
|
255
|
-
|
|
256
|
-
```typescript
|
|
257
|
-
// app/api/advanced/route.ts
|
|
258
|
-
import { getLogger } from 'securenow/tracing';
|
|
259
|
-
|
|
260
|
-
const logger = getLogger('api-handler', '1.0.0');
|
|
261
|
-
|
|
262
|
-
export async function GET() {
|
|
263
|
-
logger?.emit({
|
|
264
|
-
severityNumber: 9,
|
|
265
|
-
severityText: 'INFO',
|
|
266
|
-
body: 'Advanced API called',
|
|
267
|
-
attributes: {
|
|
268
|
-
endpoint: '/api/advanced',
|
|
269
|
-
customField: 'value',
|
|
270
|
-
},
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
return Response.json({ message: 'Success' });
|
|
274
|
-
}
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
## Troubleshooting
|
|
278
|
-
|
|
279
|
-
### Logs not appearing?
|
|
280
|
-
|
|
281
|
-
1. Check `SECURENOW_LOGGING_ENABLED=1` in `.env.local`
|
|
282
|
-
2. Verify `instrumentationHook: true` in `next.config.js`
|
|
283
|
-
3. Ensure `instrumentation.ts` is in the root (not in `app/`)
|
|
284
|
-
4. Enable debug: `OTEL_LOG_LEVEL=debug` in `.env.local`
|
|
285
|
-
5. Restart the dev server: `npm run dev`
|
|
286
|
-
|
|
287
|
-
### Console instrumentation not working?
|
|
288
|
-
|
|
289
|
-
Make sure the import order in `instrumentation.ts`:
|
|
290
|
-
|
|
291
|
-
```typescript
|
|
292
|
-
// ✅ Correct order
|
|
293
|
-
await import('securenow/register'); // First
|
|
294
|
-
await import('securenow/console-instrumentation'); // Second
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
## Next Steps
|
|
298
|
-
|
|
299
|
-
- [Complete Logging Guide](../docs/LOGGING-GUIDE.md)
|
|
300
|
-
- [Next.js Complete Guide](../docs/NEXTJS-GUIDE.md)
|
|
301
|
-
- [SecureNow](https://securenow.ai/)
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Next.js Instrumentation with SecureNow - Advanced Configuration
|
|
3
|
-
*
|
|
4
|
-
* This example shows how to pass configuration options programmatically
|
|
5
|
-
* instead of using environment variables.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { registerSecureNow } from 'securenow/nextjs';
|
|
9
|
-
|
|
10
|
-
export function register() {
|
|
11
|
-
registerSecureNow({
|
|
12
|
-
serviceName: 'my-nextjs-app',
|
|
13
|
-
endpoint: 'http://your-otlp-collector:4318',
|
|
14
|
-
noUuid: false,
|
|
15
|
-
disableInstrumentations: ['fs', 'dns'],
|
|
16
|
-
headers: {
|
|
17
|
-
'x-api-key': process.env.SECURENOW_API_KEY || '',
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* You can still use environment variables alongside options.
|
|
24
|
-
* Options take precedence over environment variables.
|
|
25
|
-
*
|
|
26
|
-
* Mix and match as needed:
|
|
27
|
-
* - Use options for static config
|
|
28
|
-
* - Use env vars for secrets and per-environment config
|
|
29
|
-
*/
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Test script to verify SecureNow Next.js setup
|
|
3
|
-
*
|
|
4
|
-
* Run this to verify your configuration before integrating with Next.js:
|
|
5
|
-
*
|
|
6
|
-
* SECURENOW_APPID=test-app node examples/test-nextjs-setup.js
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const { registerSecureNow } = require('../nextjs.js');
|
|
10
|
-
|
|
11
|
-
console.log('Testing SecureNow Next.js integration...\n');
|
|
12
|
-
|
|
13
|
-
// Test 1: Basic registration
|
|
14
|
-
console.log('Test 1: Basic registration');
|
|
15
|
-
try {
|
|
16
|
-
const sdk = registerSecureNow({
|
|
17
|
-
serviceName: 'test-nextjs-app',
|
|
18
|
-
endpoint: process.env.SECURENOW_INSTANCE || 'http://localhost:4318',
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
if (sdk) {
|
|
22
|
-
console.log('✅ SDK registered successfully\n');
|
|
23
|
-
} else {
|
|
24
|
-
console.log('⚠️ SDK returned null (expected in Edge runtime)\n');
|
|
25
|
-
}
|
|
26
|
-
} catch (error) {
|
|
27
|
-
console.error('❌ Registration failed:', error);
|
|
28
|
-
process.exit(1);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Test 2: Create a test span
|
|
32
|
-
console.log('Test 2: Creating test span');
|
|
33
|
-
try {
|
|
34
|
-
const api = require('@opentelemetry/api');
|
|
35
|
-
const tracer = api.trace.getTracer('test-tracer');
|
|
36
|
-
const span = tracer.startSpan('test.span');
|
|
37
|
-
span.setAttribute('test.attribute', 'test-value');
|
|
38
|
-
span.setAttribute('test.number', 123);
|
|
39
|
-
span.end();
|
|
40
|
-
console.log('✅ Test span created and ended\n');
|
|
41
|
-
} catch (error) {
|
|
42
|
-
console.error('❌ Span creation failed:', error);
|
|
43
|
-
process.exit(1);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Test 3: Verify configuration
|
|
47
|
-
console.log('Test 3: Configuration verification');
|
|
48
|
-
console.log('- SECURENOW_APPID:', process.env.SECURENOW_APPID || '(not set)');
|
|
49
|
-
console.log('- SECURENOW_INSTANCE:', process.env.SECURENOW_INSTANCE || '(using default)');
|
|
50
|
-
console.log('- NODE_ENV:', process.env.NODE_ENV || 'development');
|
|
51
|
-
console.log('- OTEL_LOG_LEVEL:', process.env.OTEL_LOG_LEVEL || '(none)');
|
|
52
|
-
console.log('✅ Configuration loaded\n');
|
|
53
|
-
|
|
54
|
-
// Test 4: Wait for export
|
|
55
|
-
console.log('Test 4: Waiting for span export...');
|
|
56
|
-
setTimeout(() => {
|
|
57
|
-
console.log('✅ Export should have completed\n');
|
|
58
|
-
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
59
|
-
console.log('✅ All tests passed!');
|
|
60
|
-
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
61
|
-
console.log('\nCheck your SecureNow dashboard for traces from "test-nextjs-app"\n');
|
|
62
|
-
process.exit(0);
|
|
63
|
-
}, 2000);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|