Skip to content

Commit b3a1d3f

Browse files
authored
[P-830] SDK: Server-side events Node.js SDK
2 parents 6a4b0e2 + b32199b commit b3a1d3f

19 files changed

Lines changed: 3523 additions & 424 deletions

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@ node_modules/
22
dist/
33
*.log
44
.env
5-
.DS_Store
6-
.stainless/
5+
.DS_Store

.stainless/stainless.yml

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# yaml-language-server: $schema=https://app.stainless.com/config.schema.json
2+
3+
# The main edition for the config, see the [docs] for more information.
4+
#
5+
# [docs]: https://www.stainless.com/docs/reference/editions
6+
edition: 2025-10-10
7+
8+
organization:
9+
# Name of your organization or company, used to determine the name of the client
10+
# and headings.
11+
name: Formo
12+
# Link to your API documentation.
13+
docs: 'https://docs.formo.so'
14+
# Contact email for bug reports, questions, and support requests.
15+
contact: ''
16+
17+
# `targets` define the output targets and their customization options, such as
18+
# whether to emit the Node SDK and what its package name should be.
19+
targets:
20+
typescript:
21+
# The edition for this target, see the [docs] for more information.
22+
#
23+
# [docs]: https://www.stainless.com/docs/reference/editions
24+
edition: typescript.2025-10-10
25+
package_name: '@formo/sdk-server-side'
26+
production_repo: null
27+
publish:
28+
npm: false
29+
30+
# `environments` are a map of the name of the environment (e.g. "sandbox",
31+
# "production") to the corresponding url to use.
32+
environments:
33+
production: https://events.formo.so
34+
35+
# `client_settings` define settings for the API client, such as extra constructor
36+
# arguments (used for authentication), retry behavior, idempotency, etc.
37+
client_settings:
38+
opts:
39+
api_key:
40+
type: string
41+
nullable: false
42+
read_env: FORMO_API_KEY
43+
auth:
44+
security_scheme: BearerAuth
45+
46+
# `resources` define the structure and organization for your API, such as how
47+
# methods and models are grouped together and accessed. See the [configuration
48+
# guide] for more information.
49+
#
50+
# [configuration guide]: https://www.stainless.com/docs/guides/configure#resources
51+
resources:
52+
raw_events:
53+
methods:
54+
track: post /v0/raw_events
55+
identify: post /v0/raw_events
56+
models:
57+
event: "#/components/schemas/Event"
58+
event_context: "#/components/schemas/EventContext"
59+
event_properties: "#/components/schemas/EventProperties"
60+
61+
settings:
62+
# All generated integration tests that hit the prism mock http server are marked
63+
# as skipped. Removing this setting or setting it to false enables tests, but
64+
# doing so may result in test failures due to bugs in the test server.
65+
#
66+
# [prism mock http server]: https://stoplight.io/open-source/prism
67+
68+
disable_mock_tests: true
69+
license: Apache-2.0
70+
71+
security:
72+
- BearerAuth: []
73+
74+
# `readme` is used to configure the code snippets that will be rendered in the
75+
# README.md of various SDKs. In particular, you can change the `headline`
76+
# snippet's endpoint and the arguments to call it with.
77+
readme:
78+
example_requests:
79+
default:
80+
type: request
81+
endpoint: post /v0/raw_events
82+
params:
83+
type: track
84+
channel: server
85+
version: '0'
86+
anonymous_id: user-device-uuid-123
87+
user_id: user-abc-456
88+
event: Purchase Completed
89+
properties:
90+
product_id: prod_123
91+
amount: 99.99
92+
currency: USD
93+
context:
94+
library_name: Formo Node SDK
95+
library_version: 1.0.0
96+
address: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'
97+
original_timestamp: '2025-12-23T10:00:00.000Z'
98+
sent_at: '2025-12-23T10:00:00.000Z'
99+
message_id: event-uuid-789
100+
headline:
101+
type: request
102+
endpoint: post /v0/raw_events
103+
params:
104+
type: identify
105+
channel: server
106+
version: '0'
107+
anonymous_id: user-device-uuid-123
108+
user_id: user-abc-456
109+
properties:
110+
email: user@example.com
111+
name: John Doe
112+
plan: premium
113+
context:
114+
library_name: Formo Node SDK
115+
library_version: 1.0.0
116+
address: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'
117+
original_timestamp: '2025-12-23T10:00:00.000Z'
118+
sent_at: '2025-12-23T10:00:00.000Z'
119+
message_id: event-uuid-790

.stainless/workspace.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"project": "sdk-server-side",
3+
"openapi_spec": "../openapi.json",
4+
"stainless_config": "stainless.yml",
5+
"targets": {
6+
"typescript": {
7+
"output_path": "../sdks/sdk-server-side-typescript"
8+
}
9+
}
10+
}

CONTRIBUTING.md

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
# Contributing to Formo Node SDK
2+
3+
Thank you for your interest in contributing to the Formo Node SDK! This guide will help you get started.
4+
5+
## Table of Contents
6+
7+
- [Project Structure](#project-structure)
8+
- [Setting Up the Development Environment](#setting-up-the-development-environment)
9+
- [Stainless SDK Generation](#stainless-sdk-generation)
10+
- [Making Changes](#making-changes)
11+
- [Running Tests](#running-tests)
12+
- [Code Style](#code-style)
13+
14+
## Project Structure
15+
16+
```
17+
sdk-node/
18+
├── src/ # Main SDK source code (manually maintained)
19+
│ ├── FormoAnalytics.ts # Main SDK class
20+
│ ├── queue/ # Event batching and retry logic
21+
│ ├── types/ # TypeScript type definitions
22+
│ ├── utils/ # Utilities (address checksumming, etc.)
23+
│ └── validators/ # Input validation
24+
├── sdks/
25+
│ └── sdk-server-side-typescript/ # Generated API client (via Stainless)
26+
├── openapi.json # OpenAPI specification for the Formo API
27+
├── .stainless/ # Stainless configuration
28+
│ ├── stainless.yml # Stainless SDK configuration
29+
│ └── workspace.json # Stainless workspace settings
30+
└── package.json
31+
```
32+
33+
## Setting Up the Development Environment
34+
35+
1. **Clone the repository:**
36+
37+
```bash
38+
git clone <repo-url>
39+
cd sdk-node
40+
```
41+
42+
2. **Install dependencies:**
43+
44+
This project uses [pnpm](https://pnpm.io/). Other package managers may work but are not officially supported.
45+
46+
```bash
47+
pnpm install
48+
```
49+
50+
3. **Build the project:**
51+
52+
```bash
53+
pnpm build
54+
```
55+
56+
## Stainless SDK Generation
57+
58+
This project uses [Stainless](https://www.stainless.com/) to generate type-safe API clients from our OpenAPI specification. The generated code lives in `sdks/sdk-server-side-typescript/`.
59+
60+
### Initial Setup
61+
62+
If you need to set up Stainless for the first time:
63+
64+
1. **Install the Stainless CLI:**
65+
66+
```bash
67+
brew install stainless-api/tap/stl
68+
```
69+
70+
2. **Initialize Stainless in your project:**
71+
72+
```bash
73+
stl init
74+
```
75+
76+
During initialization, you'll be prompted to:
77+
78+
- Select your OpenAPI specification file (`openapi.json`)
79+
- Choose the target language(s) (TypeScript for this project)
80+
- Configure output directories
81+
82+
3. **Configuration files:**
83+
84+
The `.stainless/` directory is included in the repository and contains:
85+
86+
- `stainless.yml` - Main configuration file for SDK generation
87+
- `workspace.json` - Workspace settings
88+
89+
Commit any changes to these files to ensure all contributors stay in sync.
90+
91+
### Regenerating the SDK
92+
93+
When the OpenAPI specification (`openapi.json`) or Stainless configuration (`.stainless/stainless.yml`) is updated, you need to regenerate the SDK:
94+
95+
```bash
96+
# Commit your changes first
97+
git add .stainless/stainless.yml openapi.json
98+
git commit -m "Update API specification"
99+
100+
# Create a new build on your current branch
101+
stl builds create --branch $(git branch --show-current)
102+
```
103+
104+
Alternatively, use development mode to see live updates and errors:
105+
106+
```bash
107+
stl dev
108+
```
109+
110+
This will regenerate the files in `sdks/sdk-server-side-typescript/` based on the current OpenAPI spec and Stainless configuration.
111+
112+
### Modifying Generated Code
113+
114+
> **Important:** Most of the code in `sdks/sdk-server-side-typescript/` is auto-generated.
115+
116+
- Modifications to generated files may persist between generations but could result in merge conflicts.
117+
- The generator will **never** modify the contents of `src/lib/` and `examples/` directories within the generated SDK.
118+
- For custom logic, prefer adding code to the main `src/` directory rather than modifying generated files.
119+
120+
### Updating the OpenAPI Specification
121+
122+
When making API changes:
123+
124+
1. Update `openapi.json` with the new endpoints, schemas, or modifications
125+
2. Update `.stainless/stainless.yml` if needed (e.g., new resources, methods, or examples)
126+
3. Validate the configuration: `stl lint`
127+
4. Commit your changes: `git add openapi.json .stainless/stainless.yml && git commit -m "Update API spec"`
128+
5. Regenerate the SDK: `stl builds create --branch $(git branch --show-current)`
129+
6. Test the changes thoroughly
130+
7. Review and commit the regenerated SDK files in `sdks/sdk-server-side-typescript/`
131+
132+
## Making Changes
133+
134+
### Main SDK Code (`src/`)
135+
136+
The core SDK logic in `src/` is manually maintained:
137+
138+
- `FormoAnalytics.ts` - Main entry point and public API
139+
- `queue/` - Event batching, retry logic, and graceful shutdown
140+
- `types/` - TypeScript interfaces and type definitions
141+
- `utils/` - Helper functions for address checksumming, property normalization
142+
- `validators/` - Input validation logic
143+
144+
When making changes:
145+
146+
1. Create a feature branch from `main`
147+
2. Make your changes with appropriate tests
148+
3. Ensure all tests pass: `pnpm test`
149+
4. Submit a pull request
150+
151+
### Generated SDK Code (`sdks/`)
152+
153+
ForUpdate `.stainless/stainless.yml` if adding new methods or resources 3. Validate with `stl lint` 4. Commit: `git add openapi.json .stainless/stainless.yml && git commit -m "Update API"` 5. Regenerate the SDK: `stl builds create --branch $(git branch --show-current)` 6. Test the changes 7. Review and commit the regeneratednapi.json`with the required changes
154+
2. Regenerate the SDK:`stainless generate` 3. Test the changes 4. Commit both files
155+
156+
## Running Tests
157+
158+
```bash
159+
# Run all tests
160+
pnpm test
161+
162+
# Run tests in watch mode
163+
pnpm test:watch
164+
165+
# Run integration tests (requires API key)
166+
FORMO_WRITE_KEY=your-key pnpm run test:integration
167+
```
168+
169+
## Code Style
170+
171+
This project uses:
172+
173+
- [Prettier](https://prettier.io/) for code formatting
174+
- [ESLint](https://eslint.org/) for linting
175+
176+
```bash
177+
# Check linting
178+
pnpm lint
179+
180+
# Fix linting and formatting issues
181+
pnpm fix
182+
```
183+
184+
## Questions?
185+
186+
If you have questions or need help, please open an issue on GitHub.

0 commit comments

Comments
 (0)