@statly/observe 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -5,6 +5,10 @@
5
5
 
6
6
  Error tracking and monitoring for JavaScript and TypeScript applications. Capture exceptions, track releases, and debug issues faster.
7
7
 
8
+ **[📚 Full Documentation](https://docs.statly.live/sdk/javascript/installation)** | **[🚀 Get Started](https://statly.live)** | **[💬 Support](mailto:support@mail.kodydennon.com)**
9
+
10
+ > **This SDK requires a [Statly](https://statly.live) account.** Sign up free at [statly.live](https://statly.live) to get your DSN and start tracking errors in minutes.
11
+
8
12
  ## Features
9
13
 
10
14
  - Automatic error capturing with stack traces
@@ -30,9 +34,21 @@ pnpm add @statly/observe
30
34
  1. Go to [statly.live/dashboard/observe/setup](https://statly.live/dashboard/observe/setup)
31
35
  2. Create an API key for Observe
32
36
  3. Copy your DSN (format: `https://<api-key>@statly.live/<org-slug>`)
37
+ 4. Add to your `.env` file: `STATLY_DSN=https://...`
33
38
 
34
39
  ## Quick Start
35
40
 
41
+ The SDK automatically loads DSN from environment variables, so you can simply:
42
+
43
+ ```typescript
44
+ import { Statly } from '@statly/observe';
45
+
46
+ // Auto-loads STATLY_DSN from environment
47
+ Statly.init();
48
+ ```
49
+
50
+ Or pass it explicitly:
51
+
36
52
  ```typescript
37
53
  import { Statly } from '@statly/observe';
38
54
 
@@ -192,11 +208,23 @@ fastify.get('/', async () => {
192
208
  fastify.listen({ port: 3000 });
193
209
  ```
194
210
 
211
+ ## Environment Variables
212
+
213
+ The SDK automatically loads configuration from environment variables:
214
+
215
+ | Variable | Description |
216
+ |----------|-------------|
217
+ | `STATLY_DSN` | Your project's DSN (primary) |
218
+ | `NEXT_PUBLIC_STATLY_DSN` | DSN for Next.js client-side |
219
+ | `STATLY_OBSERVE_DSN` | Alternative DSN variable |
220
+ | `STATLY_ENVIRONMENT` | Environment name |
221
+ | `NODE_ENV` | Fallback for environment |
222
+
195
223
  ## Configuration Options
196
224
 
197
225
  | Option | Type | Default | Description |
198
226
  |--------|------|---------|-------------|
199
- | `dsn` | `string` | **Required** | Your project's Data Source Name |
227
+ | `dsn` | `string` | `process.env.STATLY_DSN` | Your project's Data Source Name |
200
228
  | `environment` | `string` | `undefined` | Environment name (production, staging, development) |
201
229
  | `release` | `string` | `undefined` | Release/version identifier for tracking |
202
230
  | `debug` | `boolean` | `false` | Enable debug logging to console |
@@ -336,6 +364,26 @@ import type {
336
364
  - Node.js 16+
337
365
  - Works in browser environments (with bundler)
338
366
 
367
+ ## Resources
368
+
369
+ - **[Statly Platform](https://statly.live)** - Sign up and manage your error tracking
370
+ - **[Documentation](https://docs.statly.live/sdk/javascript/installation)** - Full SDK documentation
371
+ - **[API Reference](https://docs.statly.live/sdk/javascript/api-reference)** - Complete API reference
372
+ - **[Express Guide](https://docs.statly.live/sdk/javascript/express)** - Express integration
373
+ - **[Next.js Guide](https://docs.statly.live/sdk/javascript/nextjs)** - Next.js integration
374
+ - **[Fastify Guide](https://docs.statly.live/sdk/javascript/fastify)** - Fastify integration
375
+ - **[MCP Server](https://github.com/KodyDennon/DD-StatusPage/tree/master/packages/mcp-docs-server)** - AI/Claude integration for docs
376
+
377
+ ## Why Statly?
378
+
379
+ Statly is more than error tracking. Get:
380
+ - **Status Pages** - Beautiful public status pages for your users
381
+ - **Uptime Monitoring** - Multi-region HTTP/DNS checks every minute
382
+ - **Error Tracking** - SDKs for JavaScript, Python, and Go
383
+ - **Incident Management** - Track and communicate outages
384
+
385
+ All on Cloudflare's global edge network. [Start free →](https://statly.live)
386
+
339
387
  ## License
340
388
 
341
389
  MIT
@@ -886,12 +886,36 @@ function sanitizeHeaders2(headers) {
886
886
 
887
887
  // src/index.ts
888
888
  var client = null;
889
+ function loadDsnFromEnv() {
890
+ if (typeof process !== "undefined" && process.env) {
891
+ return process.env.STATLY_DSN || process.env.NEXT_PUBLIC_STATLY_DSN || process.env.STATLY_OBSERVE_DSN;
892
+ }
893
+ return void 0;
894
+ }
895
+ function loadEnvironmentFromEnv() {
896
+ if (typeof process !== "undefined" && process.env) {
897
+ return process.env.STATLY_ENVIRONMENT || process.env.NODE_ENV;
898
+ }
899
+ return void 0;
900
+ }
889
901
  function init(options) {
890
902
  if (client) {
891
903
  console.warn("[Statly] SDK already initialized. Call close() first to reinitialize.");
892
904
  return;
893
905
  }
894
- client = new StatlyClient(options);
906
+ const dsn = options?.dsn || loadDsnFromEnv();
907
+ if (!dsn) {
908
+ console.error("[Statly] No DSN provided. Set STATLY_DSN in your environment or pass dsn to init().");
909
+ console.error("[Statly] Get your DSN at https://statly.live/dashboard/observe/setup");
910
+ return;
911
+ }
912
+ const environment = options?.environment || loadEnvironmentFromEnv();
913
+ const finalOptions = {
914
+ ...options,
915
+ dsn,
916
+ environment
917
+ };
918
+ client = new StatlyClient(finalOptions);
895
919
  client.init();
896
920
  }
897
921
  function captureException(error, context) {
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/cli.js ADDED
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/cli.ts
27
+ var readline = __toESM(require("readline"));
28
+ var fs = __toESM(require("fs"));
29
+ var path = __toESM(require("path"));
30
+ var COLORS = {
31
+ reset: "\x1B[0m",
32
+ bright: "\x1B[1m",
33
+ dim: "\x1B[2m",
34
+ green: "\x1B[32m",
35
+ yellow: "\x1B[33m",
36
+ blue: "\x1B[34m",
37
+ cyan: "\x1B[36m"
38
+ };
39
+ function print(msg) {
40
+ console.log(msg);
41
+ }
42
+ function printHeader() {
43
+ print("");
44
+ print(`${COLORS.cyan}${COLORS.bright} _____ _ _ _ `);
45
+ print(`${COLORS.cyan} / ____| | | | | | `);
46
+ print(`${COLORS.cyan}| (___ | |_ __ _| |_| |_ _ `);
47
+ print(`${COLORS.cyan} \\___ \\| __/ _\` | __| | | | |`);
48
+ print(`${COLORS.cyan} ____) | || (_| | |_| | |_| |`);
49
+ print(`${COLORS.cyan}|_____/ \\__\\__,_|\\__|_|\\__, |`);
50
+ print(`${COLORS.cyan} __/ |`);
51
+ print(`${COLORS.cyan} |___/ ${COLORS.reset}`);
52
+ print("");
53
+ print(`${COLORS.bright}Statly Observe SDK Setup${COLORS.reset}`);
54
+ print(`${COLORS.dim}Error tracking for JavaScript applications${COLORS.reset}`);
55
+ print("");
56
+ }
57
+ function printStep(num, msg) {
58
+ print(`${COLORS.green}[${num}]${COLORS.reset} ${msg}`);
59
+ }
60
+ async function prompt(question) {
61
+ const rl = readline.createInterface({
62
+ input: process.stdin,
63
+ output: process.stdout
64
+ });
65
+ return new Promise((resolve) => {
66
+ rl.question(`${COLORS.yellow}?${COLORS.reset} ${question} `, (answer) => {
67
+ rl.close();
68
+ resolve(answer.trim());
69
+ });
70
+ });
71
+ }
72
+ function detectFramework() {
73
+ const packageJsonPath = path.join(process.cwd(), "package.json");
74
+ if (fs.existsSync(packageJsonPath)) {
75
+ try {
76
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
77
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
78
+ if (deps["next"]) return "nextjs";
79
+ if (deps["express"]) return "express";
80
+ if (deps["fastify"]) return "fastify";
81
+ } catch {
82
+ }
83
+ }
84
+ return null;
85
+ }
86
+ function generateCode(dsn, framework) {
87
+ if (framework === "express") {
88
+ return `// Add to your main server file (e.g., app.js or index.js)
89
+ import express from 'express';
90
+ import { Statly, requestHandler, expressErrorHandler } from '@statly/observe';
91
+
92
+ const app = express();
93
+
94
+ // Initialize Statly FIRST
95
+ Statly.init({
96
+ dsn: '${dsn}',
97
+ environment: process.env.NODE_ENV || 'development',
98
+ release: process.env.npm_package_version,
99
+ });
100
+
101
+ // Add request handler before routes
102
+ app.use(requestHandler());
103
+
104
+ // Your routes here...
105
+
106
+ // Add error handler LAST (after all routes)
107
+ app.use(expressErrorHandler());
108
+
109
+ app.listen(3000);
110
+ `;
111
+ }
112
+ if (framework === "nextjs") {
113
+ return `// Create instrumentation.ts in your project root
114
+ // instrumentation.ts
115
+ import { Statly } from '@statly/observe';
116
+
117
+ export function register() {
118
+ Statly.init({
119
+ dsn: '${dsn}',
120
+ environment: process.env.NODE_ENV || 'development',
121
+ });
122
+ }
123
+
124
+ // For API routes, wrap handlers:
125
+ // app/api/example/route.ts
126
+ import { withStatly } from '@statly/observe';
127
+
128
+ export const GET = withStatly(async (request) => {
129
+ return Response.json({ ok: true });
130
+ });
131
+
132
+ // For error boundaries:
133
+ // app/error.tsx
134
+ 'use client';
135
+ import { useEffect } from 'react';
136
+ import { captureNextJsError } from '@statly/observe';
137
+
138
+ export default function Error({ error, reset }: { error: Error; reset: () => void }) {
139
+ useEffect(() => { captureNextJsError(error); }, [error]);
140
+ return <button onClick={reset}>Try again</button>;
141
+ }
142
+ `;
143
+ }
144
+ if (framework === "fastify") {
145
+ return `// Add to your Fastify server file
146
+ import Fastify from 'fastify';
147
+ import { Statly, statlyFastifyPlugin } from '@statly/observe';
148
+
149
+ const fastify = Fastify();
150
+
151
+ // Initialize Statly
152
+ Statly.init({
153
+ dsn: '${dsn}',
154
+ environment: process.env.NODE_ENV || 'development',
155
+ });
156
+
157
+ // Register the plugin
158
+ await fastify.register(statlyFastifyPlugin, {
159
+ captureValidationErrors: true,
160
+ skipStatusCodes: [400, 401, 403, 404],
161
+ });
162
+
163
+ fastify.get('/', async () => {
164
+ return { hello: 'world' };
165
+ });
166
+
167
+ await fastify.listen({ port: 3000 });
168
+ `;
169
+ }
170
+ return `// Add to your application entry point
171
+ import { Statly } from '@statly/observe';
172
+
173
+ // Initialize the SDK
174
+ Statly.init({
175
+ dsn: '${dsn}',
176
+ environment: process.env.NODE_ENV || 'development',
177
+ release: '1.0.0', // Your app version
178
+ });
179
+
180
+ // Errors are captured automatically
181
+
182
+ // Manual capture example
183
+ try {
184
+ riskyOperation();
185
+ } catch (error) {
186
+ Statly.captureException(error);
187
+ }
188
+
189
+ // Set user context (after login)
190
+ Statly.setUser({
191
+ id: 'user-123',
192
+ email: 'user@example.com',
193
+ });
194
+
195
+ // Flush before exit (important for serverless)
196
+ await Statly.close();
197
+ `;
198
+ }
199
+ async function main() {
200
+ const args = process.argv.slice(2);
201
+ const command = args[0];
202
+ if (command === "init") {
203
+ printHeader();
204
+ print(`${COLORS.dim}Get your DSN from: https://statly.live/dashboard/observe/setup${COLORS.reset}`);
205
+ print("");
206
+ const dsn = await prompt("Enter your DSN:");
207
+ if (!dsn) {
208
+ print(`${COLORS.yellow}No DSN provided. Get one at https://statly.live${COLORS.reset}`);
209
+ process.exit(1);
210
+ }
211
+ if (!dsn.match(/^https:\/\/[^@]+@statly\.live\/.+$/)) {
212
+ print(`${COLORS.yellow}Warning: DSN format looks incorrect.${COLORS.reset}`);
213
+ print(`${COLORS.dim}Expected format: https://<api-key>@statly.live/<org-slug>${COLORS.reset}`);
214
+ }
215
+ print("");
216
+ printStep(1, "Detecting your framework...");
217
+ const framework = detectFramework();
218
+ if (framework) {
219
+ print(` ${COLORS.green}\u2713${COLORS.reset} Detected: ${COLORS.bright}${framework}${COLORS.reset}`);
220
+ } else {
221
+ print(` ${COLORS.dim}No framework detected, using generic setup${COLORS.reset}`);
222
+ }
223
+ print("");
224
+ printStep(2, "Generated setup code:");
225
+ print("");
226
+ print(`${COLORS.dim}${"\u2500".repeat(50)}${COLORS.reset}`);
227
+ print(generateCode(dsn, framework));
228
+ print(`${COLORS.dim}${"\u2500".repeat(50)}${COLORS.reset}`);
229
+ print("");
230
+ printStep(3, "Next steps:");
231
+ print(` ${COLORS.dim}1.${COLORS.reset} Copy the code above into your application`);
232
+ print(` ${COLORS.dim}2.${COLORS.reset} Set your environment variables`);
233
+ print(` ${COLORS.dim}3.${COLORS.reset} Trigger a test error to verify`);
234
+ print("");
235
+ print(`${COLORS.green}\u2713${COLORS.reset} Setup complete! View errors at ${COLORS.cyan}https://statly.live/dashboard/observe${COLORS.reset}`);
236
+ print("");
237
+ print(`${COLORS.dim}Documentation: https://docs.statly.live/sdk/javascript/installation${COLORS.reset}`);
238
+ print("");
239
+ } else {
240
+ print(`${COLORS.bright}Statly Observe CLI${COLORS.reset}`);
241
+ print("");
242
+ print("Usage:");
243
+ print(` npx @statly/observe init ${COLORS.dim}Setup Statly in your project${COLORS.reset}`);
244
+ print("");
245
+ print("Get started at https://statly.live");
246
+ }
247
+ }
248
+ main().catch(console.error);
package/dist/cli.mjs ADDED
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import * as readline from "readline";
5
+ import * as fs from "fs";
6
+ import * as path from "path";
7
+ var COLORS = {
8
+ reset: "\x1B[0m",
9
+ bright: "\x1B[1m",
10
+ dim: "\x1B[2m",
11
+ green: "\x1B[32m",
12
+ yellow: "\x1B[33m",
13
+ blue: "\x1B[34m",
14
+ cyan: "\x1B[36m"
15
+ };
16
+ function print(msg) {
17
+ console.log(msg);
18
+ }
19
+ function printHeader() {
20
+ print("");
21
+ print(`${COLORS.cyan}${COLORS.bright} _____ _ _ _ `);
22
+ print(`${COLORS.cyan} / ____| | | | | | `);
23
+ print(`${COLORS.cyan}| (___ | |_ __ _| |_| |_ _ `);
24
+ print(`${COLORS.cyan} \\___ \\| __/ _\` | __| | | | |`);
25
+ print(`${COLORS.cyan} ____) | || (_| | |_| | |_| |`);
26
+ print(`${COLORS.cyan}|_____/ \\__\\__,_|\\__|_|\\__, |`);
27
+ print(`${COLORS.cyan} __/ |`);
28
+ print(`${COLORS.cyan} |___/ ${COLORS.reset}`);
29
+ print("");
30
+ print(`${COLORS.bright}Statly Observe SDK Setup${COLORS.reset}`);
31
+ print(`${COLORS.dim}Error tracking for JavaScript applications${COLORS.reset}`);
32
+ print("");
33
+ }
34
+ function printStep(num, msg) {
35
+ print(`${COLORS.green}[${num}]${COLORS.reset} ${msg}`);
36
+ }
37
+ async function prompt(question) {
38
+ const rl = readline.createInterface({
39
+ input: process.stdin,
40
+ output: process.stdout
41
+ });
42
+ return new Promise((resolve) => {
43
+ rl.question(`${COLORS.yellow}?${COLORS.reset} ${question} `, (answer) => {
44
+ rl.close();
45
+ resolve(answer.trim());
46
+ });
47
+ });
48
+ }
49
+ function detectFramework() {
50
+ const packageJsonPath = path.join(process.cwd(), "package.json");
51
+ if (fs.existsSync(packageJsonPath)) {
52
+ try {
53
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
54
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
55
+ if (deps["next"]) return "nextjs";
56
+ if (deps["express"]) return "express";
57
+ if (deps["fastify"]) return "fastify";
58
+ } catch {
59
+ }
60
+ }
61
+ return null;
62
+ }
63
+ function generateCode(dsn, framework) {
64
+ if (framework === "express") {
65
+ return `// Add to your main server file (e.g., app.js or index.js)
66
+ import express from 'express';
67
+ import { Statly, requestHandler, expressErrorHandler } from '@statly/observe';
68
+
69
+ const app = express();
70
+
71
+ // Initialize Statly FIRST
72
+ Statly.init({
73
+ dsn: '${dsn}',
74
+ environment: process.env.NODE_ENV || 'development',
75
+ release: process.env.npm_package_version,
76
+ });
77
+
78
+ // Add request handler before routes
79
+ app.use(requestHandler());
80
+
81
+ // Your routes here...
82
+
83
+ // Add error handler LAST (after all routes)
84
+ app.use(expressErrorHandler());
85
+
86
+ app.listen(3000);
87
+ `;
88
+ }
89
+ if (framework === "nextjs") {
90
+ return `// Create instrumentation.ts in your project root
91
+ // instrumentation.ts
92
+ import { Statly } from '@statly/observe';
93
+
94
+ export function register() {
95
+ Statly.init({
96
+ dsn: '${dsn}',
97
+ environment: process.env.NODE_ENV || 'development',
98
+ });
99
+ }
100
+
101
+ // For API routes, wrap handlers:
102
+ // app/api/example/route.ts
103
+ import { withStatly } from '@statly/observe';
104
+
105
+ export const GET = withStatly(async (request) => {
106
+ return Response.json({ ok: true });
107
+ });
108
+
109
+ // For error boundaries:
110
+ // app/error.tsx
111
+ 'use client';
112
+ import { useEffect } from 'react';
113
+ import { captureNextJsError } from '@statly/observe';
114
+
115
+ export default function Error({ error, reset }: { error: Error; reset: () => void }) {
116
+ useEffect(() => { captureNextJsError(error); }, [error]);
117
+ return <button onClick={reset}>Try again</button>;
118
+ }
119
+ `;
120
+ }
121
+ if (framework === "fastify") {
122
+ return `// Add to your Fastify server file
123
+ import Fastify from 'fastify';
124
+ import { Statly, statlyFastifyPlugin } from '@statly/observe';
125
+
126
+ const fastify = Fastify();
127
+
128
+ // Initialize Statly
129
+ Statly.init({
130
+ dsn: '${dsn}',
131
+ environment: process.env.NODE_ENV || 'development',
132
+ });
133
+
134
+ // Register the plugin
135
+ await fastify.register(statlyFastifyPlugin, {
136
+ captureValidationErrors: true,
137
+ skipStatusCodes: [400, 401, 403, 404],
138
+ });
139
+
140
+ fastify.get('/', async () => {
141
+ return { hello: 'world' };
142
+ });
143
+
144
+ await fastify.listen({ port: 3000 });
145
+ `;
146
+ }
147
+ return `// Add to your application entry point
148
+ import { Statly } from '@statly/observe';
149
+
150
+ // Initialize the SDK
151
+ Statly.init({
152
+ dsn: '${dsn}',
153
+ environment: process.env.NODE_ENV || 'development',
154
+ release: '1.0.0', // Your app version
155
+ });
156
+
157
+ // Errors are captured automatically
158
+
159
+ // Manual capture example
160
+ try {
161
+ riskyOperation();
162
+ } catch (error) {
163
+ Statly.captureException(error);
164
+ }
165
+
166
+ // Set user context (after login)
167
+ Statly.setUser({
168
+ id: 'user-123',
169
+ email: 'user@example.com',
170
+ });
171
+
172
+ // Flush before exit (important for serverless)
173
+ await Statly.close();
174
+ `;
175
+ }
176
+ async function main() {
177
+ const args = process.argv.slice(2);
178
+ const command = args[0];
179
+ if (command === "init") {
180
+ printHeader();
181
+ print(`${COLORS.dim}Get your DSN from: https://statly.live/dashboard/observe/setup${COLORS.reset}`);
182
+ print("");
183
+ const dsn = await prompt("Enter your DSN:");
184
+ if (!dsn) {
185
+ print(`${COLORS.yellow}No DSN provided. Get one at https://statly.live${COLORS.reset}`);
186
+ process.exit(1);
187
+ }
188
+ if (!dsn.match(/^https:\/\/[^@]+@statly\.live\/.+$/)) {
189
+ print(`${COLORS.yellow}Warning: DSN format looks incorrect.${COLORS.reset}`);
190
+ print(`${COLORS.dim}Expected format: https://<api-key>@statly.live/<org-slug>${COLORS.reset}`);
191
+ }
192
+ print("");
193
+ printStep(1, "Detecting your framework...");
194
+ const framework = detectFramework();
195
+ if (framework) {
196
+ print(` ${COLORS.green}\u2713${COLORS.reset} Detected: ${COLORS.bright}${framework}${COLORS.reset}`);
197
+ } else {
198
+ print(` ${COLORS.dim}No framework detected, using generic setup${COLORS.reset}`);
199
+ }
200
+ print("");
201
+ printStep(2, "Generated setup code:");
202
+ print("");
203
+ print(`${COLORS.dim}${"\u2500".repeat(50)}${COLORS.reset}`);
204
+ print(generateCode(dsn, framework));
205
+ print(`${COLORS.dim}${"\u2500".repeat(50)}${COLORS.reset}`);
206
+ print("");
207
+ printStep(3, "Next steps:");
208
+ print(` ${COLORS.dim}1.${COLORS.reset} Copy the code above into your application`);
209
+ print(` ${COLORS.dim}2.${COLORS.reset} Set your environment variables`);
210
+ print(` ${COLORS.dim}3.${COLORS.reset} Trigger a test error to verify`);
211
+ print("");
212
+ print(`${COLORS.green}\u2713${COLORS.reset} Setup complete! View errors at ${COLORS.cyan}https://statly.live/dashboard/observe${COLORS.reset}`);
213
+ print("");
214
+ print(`${COLORS.dim}Documentation: https://docs.statly.live/sdk/javascript/installation${COLORS.reset}`);
215
+ print("");
216
+ } else {
217
+ print(`${COLORS.bright}Statly Observe CLI${COLORS.reset}`);
218
+ print("");
219
+ print("Usage:");
220
+ print(` npx @statly/observe init ${COLORS.dim}Setup Statly in your project${COLORS.reset}`);
221
+ print("");
222
+ print("Get started at https://statly.live");
223
+ }
224
+ }
225
+ main().catch(console.error);
package/dist/index.d.mts CHANGED
@@ -6,8 +6,11 @@ export { createRequestCapture, statlyFastifyPlugin, statlyPlugin } from './integ
6
6
  * Statly Observe SDK Types
7
7
  */
8
8
  interface StatlyOptions {
9
- /** DSN for your organization: https://<api-key>@statly.live/<org-slug> */
10
- dsn: string;
9
+ /**
10
+ * DSN for your organization: https://<api-key>@statly.live/<org-slug>
11
+ * Can be omitted if STATLY_DSN, NEXT_PUBLIC_STATLY_DSN, or STATLY_OBSERVE_DSN is set in environment
12
+ */
13
+ dsn?: string;
11
14
  /** Release/version identifier */
12
15
  release?: string;
13
16
  /** Environment (e.g., 'production', 'staging', 'development') */
@@ -110,7 +113,9 @@ declare class StatlyClient {
110
113
  private consoleIntegration;
111
114
  private user;
112
115
  private initialized;
113
- constructor(options: StatlyOptions);
116
+ constructor(options: StatlyOptions & {
117
+ dsn: string;
118
+ });
114
119
  private mergeOptions;
115
120
  private detectEnvironment;
116
121
  /**
@@ -219,8 +224,20 @@ declare class StatlyClient {
219
224
 
220
225
  /**
221
226
  * Initialize the Statly SDK
227
+ *
228
+ * DSN can be passed explicitly or loaded from environment variables:
229
+ * - STATLY_DSN
230
+ * - NEXT_PUBLIC_STATLY_DSN (for Next.js)
231
+ * - STATLY_OBSERVE_DSN
232
+ *
233
+ * @example
234
+ * // Explicit DSN
235
+ * Statly.init({ dsn: 'https://sk_live_xxx@statly.live/your-org' });
236
+ *
237
+ * // Auto-load from .env
238
+ * Statly.init(); // Uses STATLY_DSN from environment
222
239
  */
223
- declare function init(options: StatlyOptions): void;
240
+ declare function init(options?: Partial<StatlyOptions>): void;
224
241
  /**
225
242
  * Capture an exception
226
243
  */
package/dist/index.d.ts CHANGED
@@ -6,8 +6,11 @@ export { createRequestCapture, statlyFastifyPlugin, statlyPlugin } from './integ
6
6
  * Statly Observe SDK Types
7
7
  */
8
8
  interface StatlyOptions {
9
- /** DSN for your organization: https://<api-key>@statly.live/<org-slug> */
10
- dsn: string;
9
+ /**
10
+ * DSN for your organization: https://<api-key>@statly.live/<org-slug>
11
+ * Can be omitted if STATLY_DSN, NEXT_PUBLIC_STATLY_DSN, or STATLY_OBSERVE_DSN is set in environment
12
+ */
13
+ dsn?: string;
11
14
  /** Release/version identifier */
12
15
  release?: string;
13
16
  /** Environment (e.g., 'production', 'staging', 'development') */
@@ -110,7 +113,9 @@ declare class StatlyClient {
110
113
  private consoleIntegration;
111
114
  private user;
112
115
  private initialized;
113
- constructor(options: StatlyOptions);
116
+ constructor(options: StatlyOptions & {
117
+ dsn: string;
118
+ });
114
119
  private mergeOptions;
115
120
  private detectEnvironment;
116
121
  /**
@@ -219,8 +224,20 @@ declare class StatlyClient {
219
224
 
220
225
  /**
221
226
  * Initialize the Statly SDK
227
+ *
228
+ * DSN can be passed explicitly or loaded from environment variables:
229
+ * - STATLY_DSN
230
+ * - NEXT_PUBLIC_STATLY_DSN (for Next.js)
231
+ * - STATLY_OBSERVE_DSN
232
+ *
233
+ * @example
234
+ * // Explicit DSN
235
+ * Statly.init({ dsn: 'https://sk_live_xxx@statly.live/your-org' });
236
+ *
237
+ * // Auto-load from .env
238
+ * Statly.init(); // Uses STATLY_DSN from environment
222
239
  */
223
- declare function init(options: StatlyOptions): void;
240
+ declare function init(options?: Partial<StatlyOptions>): void;
224
241
  /**
225
242
  * Capture an exception
226
243
  */
package/dist/index.js CHANGED
@@ -1032,12 +1032,36 @@ function sanitizeHeaders3(headers) {
1032
1032
 
1033
1033
  // src/index.ts
1034
1034
  var client = null;
1035
+ function loadDsnFromEnv() {
1036
+ if (typeof process !== "undefined" && process.env) {
1037
+ return process.env.STATLY_DSN || process.env.NEXT_PUBLIC_STATLY_DSN || process.env.STATLY_OBSERVE_DSN;
1038
+ }
1039
+ return void 0;
1040
+ }
1041
+ function loadEnvironmentFromEnv() {
1042
+ if (typeof process !== "undefined" && process.env) {
1043
+ return process.env.STATLY_ENVIRONMENT || process.env.NODE_ENV;
1044
+ }
1045
+ return void 0;
1046
+ }
1035
1047
  function init(options) {
1036
1048
  if (client) {
1037
1049
  console.warn("[Statly] SDK already initialized. Call close() first to reinitialize.");
1038
1050
  return;
1039
1051
  }
1040
- client = new StatlyClient(options);
1052
+ const dsn = options?.dsn || loadDsnFromEnv();
1053
+ if (!dsn) {
1054
+ console.error("[Statly] No DSN provided. Set STATLY_DSN in your environment or pass dsn to init().");
1055
+ console.error("[Statly] Get your DSN at https://statly.live/dashboard/observe/setup");
1056
+ return;
1057
+ }
1058
+ const environment = options?.environment || loadEnvironmentFromEnv();
1059
+ const finalOptions = {
1060
+ ...options,
1061
+ dsn,
1062
+ environment
1063
+ };
1064
+ client = new StatlyClient(finalOptions);
1041
1065
  client.init();
1042
1066
  }
1043
1067
  function captureException(error, context) {
package/dist/index.mjs CHANGED
@@ -22,7 +22,7 @@ import {
22
22
  withStatlyGetStaticProps,
23
23
  withStatlyPagesApi,
24
24
  withStatlyServerAction
25
- } from "./chunk-PETWPVHU.mjs";
25
+ } from "./chunk-UNDSALI5.mjs";
26
26
  export {
27
27
  Statly,
28
28
  StatlyClient,
@@ -678,12 +678,36 @@ var StatlyClient = class {
678
678
 
679
679
  // src/index.ts
680
680
  var client = null;
681
+ function loadDsnFromEnv() {
682
+ if (typeof process !== "undefined" && process.env) {
683
+ return process.env.STATLY_DSN || process.env.NEXT_PUBLIC_STATLY_DSN || process.env.STATLY_OBSERVE_DSN;
684
+ }
685
+ return void 0;
686
+ }
687
+ function loadEnvironmentFromEnv() {
688
+ if (typeof process !== "undefined" && process.env) {
689
+ return process.env.STATLY_ENVIRONMENT || process.env.NODE_ENV;
690
+ }
691
+ return void 0;
692
+ }
681
693
  function init(options) {
682
694
  if (client) {
683
695
  console.warn("[Statly] SDK already initialized. Call close() first to reinitialize.");
684
696
  return;
685
697
  }
686
- client = new StatlyClient(options);
698
+ const dsn = options?.dsn || loadDsnFromEnv();
699
+ if (!dsn) {
700
+ console.error("[Statly] No DSN provided. Set STATLY_DSN in your environment or pass dsn to init().");
701
+ console.error("[Statly] Get your DSN at https://statly.live/dashboard/observe/setup");
702
+ return;
703
+ }
704
+ const environment = options?.environment || loadEnvironmentFromEnv();
705
+ const finalOptions = {
706
+ ...options,
707
+ dsn,
708
+ environment
709
+ };
710
+ client = new StatlyClient(finalOptions);
687
711
  client.init();
688
712
  }
689
713
  function captureException(error, context) {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  expressErrorHandler,
3
3
  requestHandler
4
- } from "../chunk-PETWPVHU.mjs";
4
+ } from "../chunk-UNDSALI5.mjs";
5
5
  export {
6
6
  expressErrorHandler,
7
7
  requestHandler
@@ -679,12 +679,36 @@ var StatlyClient = class {
679
679
 
680
680
  // src/index.ts
681
681
  var client = null;
682
+ function loadDsnFromEnv() {
683
+ if (typeof process !== "undefined" && process.env) {
684
+ return process.env.STATLY_DSN || process.env.NEXT_PUBLIC_STATLY_DSN || process.env.STATLY_OBSERVE_DSN;
685
+ }
686
+ return void 0;
687
+ }
688
+ function loadEnvironmentFromEnv() {
689
+ if (typeof process !== "undefined" && process.env) {
690
+ return process.env.STATLY_ENVIRONMENT || process.env.NODE_ENV;
691
+ }
692
+ return void 0;
693
+ }
682
694
  function init(options) {
683
695
  if (client) {
684
696
  console.warn("[Statly] SDK already initialized. Call close() first to reinitialize.");
685
697
  return;
686
698
  }
687
- client = new StatlyClient(options);
699
+ const dsn = options?.dsn || loadDsnFromEnv();
700
+ if (!dsn) {
701
+ console.error("[Statly] No DSN provided. Set STATLY_DSN in your environment or pass dsn to init().");
702
+ console.error("[Statly] Get your DSN at https://statly.live/dashboard/observe/setup");
703
+ return;
704
+ }
705
+ const environment = options?.environment || loadEnvironmentFromEnv();
706
+ const finalOptions = {
707
+ ...options,
708
+ dsn,
709
+ environment
710
+ };
711
+ client = new StatlyClient(finalOptions);
688
712
  client.init();
689
713
  }
690
714
  function captureException(error, context) {
@@ -2,7 +2,7 @@ import {
2
2
  createRequestCapture,
3
3
  statlyFastifyPlugin,
4
4
  statlyPlugin
5
- } from "../chunk-PETWPVHU.mjs";
5
+ } from "../chunk-UNDSALI5.mjs";
6
6
  export {
7
7
  createRequestCapture,
8
8
  statlyFastifyPlugin,
@@ -682,12 +682,36 @@ var StatlyClient = class {
682
682
 
683
683
  // src/index.ts
684
684
  var client = null;
685
+ function loadDsnFromEnv() {
686
+ if (typeof process !== "undefined" && process.env) {
687
+ return process.env.STATLY_DSN || process.env.NEXT_PUBLIC_STATLY_DSN || process.env.STATLY_OBSERVE_DSN;
688
+ }
689
+ return void 0;
690
+ }
691
+ function loadEnvironmentFromEnv() {
692
+ if (typeof process !== "undefined" && process.env) {
693
+ return process.env.STATLY_ENVIRONMENT || process.env.NODE_ENV;
694
+ }
695
+ return void 0;
696
+ }
685
697
  function init(options) {
686
698
  if (client) {
687
699
  console.warn("[Statly] SDK already initialized. Call close() first to reinitialize.");
688
700
  return;
689
701
  }
690
- client = new StatlyClient(options);
702
+ const dsn = options?.dsn || loadDsnFromEnv();
703
+ if (!dsn) {
704
+ console.error("[Statly] No DSN provided. Set STATLY_DSN in your environment or pass dsn to init().");
705
+ console.error("[Statly] Get your DSN at https://statly.live/dashboard/observe/setup");
706
+ return;
707
+ }
708
+ const environment = options?.environment || loadEnvironmentFromEnv();
709
+ const finalOptions = {
710
+ ...options,
711
+ dsn,
712
+ environment
713
+ };
714
+ client = new StatlyClient(finalOptions);
691
715
  client.init();
692
716
  }
693
717
  function captureException(error, context) {
@@ -5,7 +5,7 @@ import {
5
5
  withStatlyGetStaticProps,
6
6
  withStatlyPagesApi,
7
7
  withStatlyServerAction
8
- } from "../chunk-PETWPVHU.mjs";
8
+ } from "../chunk-UNDSALI5.mjs";
9
9
  export {
10
10
  captureNextJsError,
11
11
  withStatly,
package/package.json CHANGED
@@ -1,10 +1,13 @@
1
1
  {
2
2
  "name": "@statly/observe",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "JavaScript SDK for Statly Observe - Error tracking and monitoring",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "statly-observe": "./dist/cli.js"
10
+ },
8
11
  "exports": {
9
12
  ".": {
10
13
  "types": "./dist/index.d.ts",
@@ -30,10 +33,11 @@
30
33
  "files": [
31
34
  "dist",
32
35
  "README.md",
33
- "LICENSE"
36
+ "LICENSE",
37
+ "bin"
34
38
  ],
35
39
  "scripts": {
36
- "build": "tsup src/index.ts src/integrations/express.ts src/integrations/nextjs.ts src/integrations/fastify.ts --format cjs,esm --dts --clean",
40
+ "build": "tsup src/index.ts src/integrations/express.ts src/integrations/nextjs.ts src/integrations/fastify.ts src/cli.ts --format cjs,esm --dts --clean",
37
41
  "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
38
42
  "lint": "eslint src --ext .ts",
39
43
  "test": "vitest run",
@@ -49,7 +53,7 @@
49
53
  "error-monitoring",
50
54
  "exception-tracking"
51
55
  ],
52
- "author": "Statly <support@statly.live>",
56
+ "author": "Statly <support@mail.kodydennon.com>",
53
57
  "license": "MIT",
54
58
  "homepage": "https://statly.live",
55
59
  "repository": {
@@ -60,6 +64,7 @@
60
64
  "url": "https://github.com/KodyDennon/statly-node/issues"
61
65
  },
62
66
  "devDependencies": {
67
+ "@types/node": "^20.0.0",
63
68
  "tsup": "^8.0.0",
64
69
  "typescript": "^5.0.0",
65
70
  "vitest": "^1.0.0"