@ewyn/client 0.2.0 → 0.3.0
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 +53 -5
- package/dist/__tests__/cli-fetch-config.test.d.ts +2 -0
- package/dist/__tests__/cli-fetch-config.test.d.ts.map +1 -0
- package/dist/__tests__/cli-fetch-config.test.js +70 -0
- package/dist/__tests__/dashboard-config.test.js +1 -6
- package/dist/__tests__/errors.test.js +1 -1
- package/dist/__tests__/ewyn.test.js +1 -2
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +140 -0
- package/dist/index.d.ts +1 -49
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/types.d.ts +12 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -27,7 +27,6 @@ import { Ewyn } from '@ewyn/client';
|
|
|
27
27
|
const client = new Ewyn({
|
|
28
28
|
workspaceId: 'your-workspace-id',
|
|
29
29
|
apiKey: 'your-api-key',
|
|
30
|
-
baseUrl: 'https://www.ewyn.ai/api/v1', // optional; omit to use production default
|
|
31
30
|
});
|
|
32
31
|
|
|
33
32
|
// Send an email using template version ID
|
|
@@ -91,7 +90,58 @@ await client.send({
|
|
|
91
90
|
|
|
92
91
|
## Getting Your Template Configuration
|
|
93
92
|
|
|
94
|
-
|
|
93
|
+
You can get your template config in three ways:
|
|
94
|
+
|
|
95
|
+
1. **CLI (recommended)** – Run `npx @ewyn/client fetch-config` to download config and generate `ewynTemplates.ts` (see [Fetching template config (CLI)](#fetching-template-config-cli)).
|
|
96
|
+
2. **Dashboard** – Copy JSON from the API Keys page.
|
|
97
|
+
3. **API** – Call the templates config endpoint with curl or your own code.
|
|
98
|
+
|
|
99
|
+
### Fetching template config (CLI)
|
|
100
|
+
|
|
101
|
+
The easiest way to keep your template config in sync is to use the built-in CLI. From your project root (where you have an `ewyn.config.ts` or `ewyn.config.js`), run:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npx @ewyn/client fetch-config
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
This fetches your workspace’s template config from the API and writes a TypeScript file (e.g. `ewynTemplates.ts`) that you can import for type-safe sending.
|
|
108
|
+
|
|
109
|
+
**Config file** (`ewyn.config.ts` in project root):
|
|
110
|
+
|
|
111
|
+
- `workspaceId` (required): Your workspace UUID (e.g. `process.env.EWYN_WORKSPACE_ID`)
|
|
112
|
+
- `apiKey` (required): Your API key (e.g. `process.env.EWYN_API_KEY`)
|
|
113
|
+
- `configurationPath` (optional): Where to write the generated file (e.g. `./src/ewynTemplates.ts`). If omitted, the file is written as `./ewynTemplates.ts` in the current directory.
|
|
114
|
+
|
|
115
|
+
Example `ewyn.config.ts`:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import type { EwynFetchConfig } from '@ewyn/client';
|
|
119
|
+
|
|
120
|
+
const config: EwynFetchConfig = {
|
|
121
|
+
workspaceId: process.env.EWYN_WORKSPACE_ID!,
|
|
122
|
+
apiKey: process.env.EWYN_API_KEY!,
|
|
123
|
+
configurationPath: './src/ewynTemplates.ts', // optional
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export default config;
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
After running `fetch-config`, import the generated config and pass it to the client:
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { Ewyn } from '@ewyn/client';
|
|
133
|
+
import { ewynTemplates } from './ewynTemplates'; // or from your configurationPath
|
|
134
|
+
|
|
135
|
+
const client = new Ewyn({
|
|
136
|
+
workspaceId: process.env.EWYN_WORKSPACE_ID!,
|
|
137
|
+
apiKey: process.env.EWYN_API_KEY!,
|
|
138
|
+
templates: ewynTemplates,
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**Note:** Regenerate the config after creating or updating templates (re-run `npx @ewyn/client fetch-config`).
|
|
143
|
+
|
|
144
|
+
### From Dashboard
|
|
95
145
|
|
|
96
146
|
1. Go to your dashboard → **API Keys** page
|
|
97
147
|
2. Scroll to **Template Configuration** section
|
|
@@ -119,8 +169,6 @@ curl -X GET https://www.ewyn.ai/api/v1/workspaces/YOUR_WORKSPACE_ID/templates/co
|
|
|
119
169
|
-H "Authorization: Bearer YOUR_API_KEY"
|
|
120
170
|
```
|
|
121
171
|
|
|
122
|
-
**Note:** Regenerate the config after creating or updating templates to keep it in sync.
|
|
123
|
-
|
|
124
172
|
## API Reference
|
|
125
173
|
|
|
126
174
|
### `Ewyn` Class
|
|
@@ -135,7 +183,6 @@ new Ewyn(options: EwynOptions)
|
|
|
135
183
|
|
|
136
184
|
- `workspaceId` (string, required): Your workspace UUID
|
|
137
185
|
- `apiKey` (string, required): Your API key secret
|
|
138
|
-
- `baseUrl` (string, optional): Base URL for the API (defaults to `https://www.ewyn.ai/api/v1`)
|
|
139
186
|
- `templates` (TemplateConfig, optional): Template configuration for name-based sending
|
|
140
187
|
- `maxRetries` (number, optional): Maximum retries for retryable errors (default: 3)
|
|
141
188
|
- `timeout` (number, optional): Request timeout in milliseconds (default: 30000)
|
|
@@ -235,6 +282,7 @@ Check out the [examples directory](./examples/) for comprehensive examples:
|
|
|
235
282
|
|
|
236
283
|
- [Basic send](./examples/basic-send.ts) - Simple sending with template ID
|
|
237
284
|
- [Type-safe usage](./examples/with-template-config.ts) - Full type safety with template config
|
|
285
|
+
- [ewyn.config example](./examples/ewyn.config.example.ts) - Example config for `fetch-config` CLI
|
|
238
286
|
- [Error handling](./examples/error-handling.ts) - Comprehensive error handling patterns
|
|
239
287
|
- [Idempotency](./examples/idempotency.ts) - Preventing duplicate sends
|
|
240
288
|
- [Advanced patterns](./examples/advanced-usage.ts) - Batch sending, retries, and more
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-fetch-config.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/cli-fetch-config.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { runFetchConfig } from '../cli.js';
|
|
6
|
+
const MOCK_TEMPLATES = {
|
|
7
|
+
welcome: {
|
|
8
|
+
id: 'version-uuid-1',
|
|
9
|
+
name: 'Welcome Email',
|
|
10
|
+
version: 1,
|
|
11
|
+
vars: {
|
|
12
|
+
firstName: { required: true },
|
|
13
|
+
lastName: { required: false },
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
describe('fetch-config CLI', () => {
|
|
18
|
+
let tempDir;
|
|
19
|
+
let originalFetch;
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ewyn-cli-test-'));
|
|
22
|
+
originalFetch = globalThis.fetch;
|
|
23
|
+
globalThis.fetch = vi.fn().mockResolvedValue({
|
|
24
|
+
ok: true,
|
|
25
|
+
json: async () => ({ templates: MOCK_TEMPLATES }),
|
|
26
|
+
text: async () => '',
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
globalThis.fetch = originalFetch;
|
|
31
|
+
vi.restoreAllMocks();
|
|
32
|
+
try {
|
|
33
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// ignore
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
it('writes ewynTemplates.ts with fetched config when using default path', async () => {
|
|
40
|
+
const configPath = path.join(tempDir, 'ewyn.config.js');
|
|
41
|
+
fs.writeFileSync(configPath, `export default {
|
|
42
|
+
workspaceId: 'test-workspace-id',
|
|
43
|
+
apiKey: 'test-api-key',
|
|
44
|
+
};
|
|
45
|
+
`, 'utf-8');
|
|
46
|
+
await runFetchConfig(tempDir);
|
|
47
|
+
const outputPath = path.join(tempDir, 'ewynTemplates.ts');
|
|
48
|
+
expect(fs.existsSync(outputPath)).toBe(true);
|
|
49
|
+
const content = fs.readFileSync(outputPath, 'utf-8');
|
|
50
|
+
expect(content).toContain('// Generated by @ewyn/client fetch-config');
|
|
51
|
+
expect(content).toContain('export const ewynTemplates = ');
|
|
52
|
+
expect(content).toContain('"welcome"');
|
|
53
|
+
expect(content).toContain('"version-uuid-1"');
|
|
54
|
+
expect(content).toContain(' as const;');
|
|
55
|
+
});
|
|
56
|
+
it('writes to configurationPath when set in config', async () => {
|
|
57
|
+
const configPath = path.join(tempDir, 'ewyn.config.js');
|
|
58
|
+
fs.writeFileSync(configPath, `export default {
|
|
59
|
+
workspaceId: 'ws-1',
|
|
60
|
+
apiKey: 'key-1',
|
|
61
|
+
configurationPath: './src/ewynTemplates.ts',
|
|
62
|
+
};
|
|
63
|
+
`, 'utf-8');
|
|
64
|
+
await runFetchConfig(tempDir);
|
|
65
|
+
const outputPath = path.join(tempDir, 'src', 'ewynTemplates.ts');
|
|
66
|
+
expect(fs.existsSync(outputPath)).toBe(true);
|
|
67
|
+
const content = fs.readFileSync(outputPath, 'utf-8');
|
|
68
|
+
expect(content).toContain('"welcome"');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -48,7 +48,6 @@ describe('Dashboard config (runtime)', () => {
|
|
|
48
48
|
const client = new Ewyn({
|
|
49
49
|
workspaceId: 'ws-1',
|
|
50
50
|
apiKey: 'key-1',
|
|
51
|
-
baseUrl: 'https://api.test.com/api/v1',
|
|
52
51
|
templates: configOnlyRequired,
|
|
53
52
|
maxRetries: 1,
|
|
54
53
|
timeout: 5000,
|
|
@@ -72,7 +71,7 @@ describe('Dashboard config (runtime)', () => {
|
|
|
72
71
|
},
|
|
73
72
|
});
|
|
74
73
|
expect(result).toEqual(mockResponse);
|
|
75
|
-
expect(global.fetch).toHaveBeenCalledWith('https://
|
|
74
|
+
expect(global.fetch).toHaveBeenCalledWith('https://www.ewyn.ai/api/v1/workspaces/ws-1/send', expect.objectContaining({
|
|
76
75
|
method: 'POST',
|
|
77
76
|
body: expect.stringContaining('"templateId":"version-uuid-1"'),
|
|
78
77
|
}));
|
|
@@ -84,7 +83,6 @@ describe('Dashboard config (runtime)', () => {
|
|
|
84
83
|
const client = new Ewyn({
|
|
85
84
|
workspaceId: 'ws-2',
|
|
86
85
|
apiKey: 'key-2',
|
|
87
|
-
baseUrl: 'https://api.test.com/api/v1',
|
|
88
86
|
templates: configMixedVars,
|
|
89
87
|
maxRetries: 1,
|
|
90
88
|
timeout: 5000,
|
|
@@ -120,7 +118,6 @@ describe('Dashboard config (runtime)', () => {
|
|
|
120
118
|
const client = new Ewyn({
|
|
121
119
|
workspaceId: 'ws-3',
|
|
122
120
|
apiKey: 'key-3',
|
|
123
|
-
baseUrl: 'https://api.test.com/api/v1',
|
|
124
121
|
templates: configEmptyVars,
|
|
125
122
|
maxRetries: 1,
|
|
126
123
|
timeout: 5000,
|
|
@@ -150,7 +147,6 @@ describe('Dashboard config (runtime)', () => {
|
|
|
150
147
|
const client = new Ewyn({
|
|
151
148
|
workspaceId: 'ws-1',
|
|
152
149
|
apiKey: 'key-1',
|
|
153
|
-
baseUrl: 'https://api.test.com/api/v1',
|
|
154
150
|
templates: configOnlyRequired,
|
|
155
151
|
maxRetries: 1,
|
|
156
152
|
timeout: 5000,
|
|
@@ -168,7 +164,6 @@ describe('Dashboard config (runtime)', () => {
|
|
|
168
164
|
const client = new Ewyn({
|
|
169
165
|
workspaceId: 'ws-1',
|
|
170
166
|
apiKey: 'key-1',
|
|
171
|
-
baseUrl: 'https://api.test.com/api/v1',
|
|
172
167
|
templates: configOnlyRequired,
|
|
173
168
|
maxRetries: 1,
|
|
174
169
|
timeout: 5000,
|
|
@@ -10,7 +10,6 @@ describe('Ewyn SDK', () => {
|
|
|
10
10
|
client = new Ewyn({
|
|
11
11
|
workspaceId: 'test-workspace-id',
|
|
12
12
|
apiKey: 'test-api-key',
|
|
13
|
-
baseUrl: 'https://api.test.com/api/v1',
|
|
14
13
|
maxRetries: 2, // Allow 1 retry (attempt < maxRetries)
|
|
15
14
|
timeout: 5000,
|
|
16
15
|
});
|
|
@@ -65,7 +64,7 @@ describe('Ewyn SDK', () => {
|
|
|
65
64
|
},
|
|
66
65
|
});
|
|
67
66
|
expect(result).toEqual(mockResponse);
|
|
68
|
-
expect(global.fetch).toHaveBeenCalledWith('https://
|
|
67
|
+
expect(global.fetch).toHaveBeenCalledWith('https://www.ewyn.ai/api/v1/workspaces/test-workspace-id/send', expect.objectContaining({
|
|
69
68
|
method: 'POST',
|
|
70
69
|
headers: expect.objectContaining({
|
|
71
70
|
'Content-Type': 'application/json',
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA+GA,4BAA4B;AAC5B,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB/D"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { pathToFileURL } from 'node:url';
|
|
6
|
+
const EWYN_API_BASE_URL = 'https://www.ewyn.ai/api/v1';
|
|
7
|
+
const CONFIG_NAMES = ['ewyn.config.ts', 'ewyn.config.mjs', 'ewyn.config.js'];
|
|
8
|
+
const DEFAULT_OUTPUT_FILE = 'ewynTemplates.ts';
|
|
9
|
+
function printUsage() {
|
|
10
|
+
console.error(`
|
|
11
|
+
Usage: ewyn <command>
|
|
12
|
+
|
|
13
|
+
Commands:
|
|
14
|
+
fetch-config Fetch template config from the API and write ewynTemplates.ts (or configurationPath from ewyn.config)
|
|
15
|
+
|
|
16
|
+
Config file (in current working directory):
|
|
17
|
+
Look for ewyn.config.ts, ewyn.config.mjs, or ewyn.config.js with default export:
|
|
18
|
+
{ workspaceId: string, apiKey: string, configurationPath?: string }
|
|
19
|
+
|
|
20
|
+
Example ewyn.config.ts:
|
|
21
|
+
export default {
|
|
22
|
+
workspaceId: process.env.EWYN_WORKSPACE_ID!,
|
|
23
|
+
apiKey: process.env.EWYN_API_KEY!,
|
|
24
|
+
configurationPath: './src/ewynTemplates.ts', // optional
|
|
25
|
+
};
|
|
26
|
+
`);
|
|
27
|
+
}
|
|
28
|
+
function findConfigPath(cwd) {
|
|
29
|
+
for (const name of CONFIG_NAMES) {
|
|
30
|
+
const p = path.join(cwd, name);
|
|
31
|
+
if (fs.existsSync(p))
|
|
32
|
+
return p;
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
async function loadConfig(configPath) {
|
|
37
|
+
const ext = path.extname(configPath);
|
|
38
|
+
if (ext === '.ts') {
|
|
39
|
+
const require = createRequire(import.meta.url);
|
|
40
|
+
const { register } = require('tsx/cjs');
|
|
41
|
+
register();
|
|
42
|
+
const mod = require(configPath);
|
|
43
|
+
const config = mod?.default;
|
|
44
|
+
if (!config || typeof config !== 'object') {
|
|
45
|
+
throw new Error(`${configPath}: expected default export to be a config object`);
|
|
46
|
+
}
|
|
47
|
+
return config;
|
|
48
|
+
}
|
|
49
|
+
const mod = await import(pathToFileURL(configPath).href);
|
|
50
|
+
const config = mod?.default;
|
|
51
|
+
if (!config || typeof config !== 'object') {
|
|
52
|
+
throw new Error(`${configPath}: expected default export to be a config object`);
|
|
53
|
+
}
|
|
54
|
+
return config;
|
|
55
|
+
}
|
|
56
|
+
function validateConfig(config, configPath) {
|
|
57
|
+
if (!config.workspaceId || typeof config.workspaceId !== 'string') {
|
|
58
|
+
console.error(`Error: workspaceId is missing or invalid in ${configPath}. You can use process.env.EWYN_WORKSPACE_ID.`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
if (!config.apiKey || typeof config.apiKey !== 'string') {
|
|
62
|
+
console.error(`Error: apiKey is missing or invalid in ${configPath}. You can use process.env.EWYN_API_KEY.`);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function fetchTemplates(workspaceId, apiKey) {
|
|
67
|
+
const url = `${EWYN_API_BASE_URL}/workspaces/${workspaceId}/templates/config`;
|
|
68
|
+
const response = await fetch(url, {
|
|
69
|
+
method: 'GET',
|
|
70
|
+
headers: {
|
|
71
|
+
Authorization: `Bearer ${apiKey}`,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
const body = await response.text();
|
|
76
|
+
let details = body;
|
|
77
|
+
try {
|
|
78
|
+
const json = JSON.parse(body);
|
|
79
|
+
details = json.error ?? json.message ?? body;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// use raw body
|
|
83
|
+
}
|
|
84
|
+
console.error(`Error: API request failed (${response.status}): ${details}`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
const data = (await response.json());
|
|
88
|
+
const templates = data.templates ?? {};
|
|
89
|
+
return templates;
|
|
90
|
+
}
|
|
91
|
+
function serializeTemplates(templates) {
|
|
92
|
+
const lines = ['// Generated by @ewyn/client fetch-config. Do not edit by hand.', '', 'export const ewynTemplates = '];
|
|
93
|
+
const json = JSON.stringify(templates, null, 2);
|
|
94
|
+
// Ensure valid TS: escape any stray characters and add "as const"
|
|
95
|
+
lines.push(json + ' as const;');
|
|
96
|
+
return lines.join('\n');
|
|
97
|
+
}
|
|
98
|
+
/** Exported for testing. */
|
|
99
|
+
export async function runFetchConfig(cwd) {
|
|
100
|
+
const configPath = findConfigPath(cwd);
|
|
101
|
+
if (!configPath) {
|
|
102
|
+
console.error('Error: ewyn.config.ts (or ewyn.config.mjs / ewyn.config.js) not found in current directory.');
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
const config = await loadConfig(configPath);
|
|
106
|
+
validateConfig(config, configPath);
|
|
107
|
+
const outputPath = config.configurationPath
|
|
108
|
+
? path.resolve(cwd, config.configurationPath)
|
|
109
|
+
: path.join(cwd, DEFAULT_OUTPUT_FILE);
|
|
110
|
+
const templates = await fetchTemplates(config.workspaceId, config.apiKey);
|
|
111
|
+
const dir = path.dirname(outputPath);
|
|
112
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
113
|
+
fs.writeFileSync(outputPath, serializeTemplates(templates), 'utf-8');
|
|
114
|
+
console.log(`Wrote ${outputPath}`);
|
|
115
|
+
}
|
|
116
|
+
async function main() {
|
|
117
|
+
const args = process.argv.slice(2);
|
|
118
|
+
const command = args[0];
|
|
119
|
+
if (!command || command === '--help' || command === '-h') {
|
|
120
|
+
printUsage();
|
|
121
|
+
process.exit(0);
|
|
122
|
+
}
|
|
123
|
+
if (command === 'fetch-config') {
|
|
124
|
+
const cwd = process.cwd();
|
|
125
|
+
await runFetchConfig(cwd);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
console.error(`Error: unknown command "${command}".`);
|
|
129
|
+
printUsage();
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
const isMain = typeof process !== 'undefined' &&
|
|
133
|
+
process.argv[1] &&
|
|
134
|
+
pathToFileURL(process.argv[1]).href === import.meta.url;
|
|
135
|
+
if (isMain) {
|
|
136
|
+
main().catch((err) => {
|
|
137
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
138
|
+
process.exit(1);
|
|
139
|
+
});
|
|
140
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,55 +1,7 @@
|
|
|
1
1
|
import type { EwynOptions, EwynOptionsTyped, SendEmailOptions, SendEmailOptionsTyped, SendEmailResponse, TemplateConfig } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Ewyn SDK Client
|
|
4
|
-
*
|
|
5
|
-
* @example Basic usage without template config
|
|
6
|
-
* ```ts
|
|
7
|
-
* const client = new Ewyn({
|
|
8
|
-
* workspaceId: 'your-workspace-id',
|
|
9
|
-
* apiKey: 'your-api-key',
|
|
10
|
-
* });
|
|
11
|
-
*
|
|
12
|
-
* await client.send({
|
|
13
|
-
* to: 'user@example.com',
|
|
14
|
-
* templateId: 'version-uuid',
|
|
15
|
-
* variables: { firstName: 'John' }
|
|
16
|
-
* });
|
|
17
|
-
* ```
|
|
18
|
-
*
|
|
19
|
-
* @example Type-safe usage with template config
|
|
20
|
-
* ```ts
|
|
21
|
-
* const config = {
|
|
22
|
-
* welcome: {
|
|
23
|
-
* id: 'version-uuid',
|
|
24
|
-
* name: 'Welcome Email',
|
|
25
|
-
* version: 1,
|
|
26
|
-
* vars: {
|
|
27
|
-
* firstName: { required: true },
|
|
28
|
-
* plan: { required: false }
|
|
29
|
-
* }
|
|
30
|
-
* }
|
|
31
|
-
* } as const;
|
|
32
|
-
*
|
|
33
|
-
* const client = new Ewyn({
|
|
34
|
-
* workspaceId: 'your-workspace-id',
|
|
35
|
-
* apiKey: 'your-api-key',
|
|
36
|
-
* templates: config
|
|
37
|
-
* });
|
|
38
|
-
*
|
|
39
|
-
* // Type-safe sending
|
|
40
|
-
* await client.send({
|
|
41
|
-
* to: 'user@example.com',
|
|
42
|
-
* template: 'welcome', // Autocomplete available
|
|
43
|
-
* variables: {
|
|
44
|
-
* firstName: 'John' // TypeScript enforces required vars
|
|
45
|
-
* }
|
|
46
|
-
* });
|
|
47
|
-
* ```
|
|
48
|
-
*/
|
|
49
2
|
export declare class Ewyn<TConfig extends TemplateConfig = TemplateConfig> {
|
|
50
3
|
private readonly workspaceId;
|
|
51
4
|
private readonly apiKey;
|
|
52
|
-
private readonly baseUrl;
|
|
53
5
|
private readonly templates?;
|
|
54
6
|
private readonly maxRetries;
|
|
55
7
|
private readonly timeout;
|
|
@@ -95,5 +47,5 @@ export declare class Ewyn<TConfig extends TemplateConfig = TemplateConfig> {
|
|
|
95
47
|
private requestWithRetry;
|
|
96
48
|
}
|
|
97
49
|
export { EwynApiError } from './errors.js';
|
|
98
|
-
export type { EwynOptions, EwynOptionsTyped, SendEmailOptions, SendEmailOptionsBase, SendEmailOptionsTyped, SendEmailResponse, TemplateConfig, TemplateConfigEntry, TemplateVariable
|
|
50
|
+
export type { EwynFetchConfig, EwynOptions, EwynOptionsTyped, SendEmailOptions, SendEmailOptionsBase, SendEmailOptionsTyped, SendEmailResponse, TemplateConfig, TemplateConfigEntry, TemplateVariable } from './types.js';
|
|
99
51
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACf,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACf,MAAM,YAAY,CAAC;AAmDpB,qBAAa,IAAI,CAAC,OAAO,SAAS,cAAc,GAAG,cAAc;IAC/D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAU;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,EAAE,WAAW,GAAG,gBAAgB,CAAC,OAAO,CAAC;IAQ5D;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACG,IAAI,CACR,OAAO,EAAE,OAAO,SAAS,cAAc,GACnC,qBAAqB,CAAC,OAAO,CAAC,GAAG,gBAAgB,GACjD,gBAAgB,GACnB,OAAO,CAAC,iBAAiB,CAAC;IA8C7B;;OAEG;YACW,iBAAiB;IAyB/B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA2BzB;;OAEG;YACW,gBAAgB;CAuE/B;AAED,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,YAAY,EACV,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -46,17 +46,16 @@ import { EwynApiError } from './errors.js';
|
|
|
46
46
|
* });
|
|
47
47
|
* ```
|
|
48
48
|
*/
|
|
49
|
+
const EWYN_API_BASE_URL = 'https://www.ewyn.ai/api/v1';
|
|
49
50
|
export class Ewyn {
|
|
50
51
|
workspaceId;
|
|
51
52
|
apiKey;
|
|
52
|
-
baseUrl;
|
|
53
53
|
templates;
|
|
54
54
|
maxRetries;
|
|
55
55
|
timeout;
|
|
56
56
|
constructor(options) {
|
|
57
57
|
this.workspaceId = options.workspaceId;
|
|
58
58
|
this.apiKey = options.apiKey;
|
|
59
|
-
this.baseUrl = options.baseUrl || 'https://www.ewyn.ai/api/v1';
|
|
60
59
|
this.templates = options.templates;
|
|
61
60
|
this.maxRetries = options.maxRetries ?? 3;
|
|
62
61
|
this.timeout = options.timeout ?? 30000;
|
|
@@ -166,7 +165,7 @@ export class Ewyn {
|
|
|
166
165
|
* Make HTTP request with retry logic
|
|
167
166
|
*/
|
|
168
167
|
async requestWithRetry(path, init, attempt = 1) {
|
|
169
|
-
const url = `${
|
|
168
|
+
const url = `${EWYN_API_BASE_URL}${path}`;
|
|
170
169
|
const controller = new AbortController();
|
|
171
170
|
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
172
171
|
try {
|
package/dist/types.d.ts
CHANGED
|
@@ -104,8 +104,6 @@ export interface EwynOptionsBase {
|
|
|
104
104
|
workspaceId: string;
|
|
105
105
|
/** API key secret */
|
|
106
106
|
apiKey: string;
|
|
107
|
-
/** Base URL for the API (defaults to production) */
|
|
108
|
-
baseUrl?: string;
|
|
109
107
|
/** Maximum number of retries for retryable errors (default: 3) */
|
|
110
108
|
maxRetries?: number;
|
|
111
109
|
/** Request timeout in milliseconds (default: 30000) */
|
|
@@ -125,5 +123,17 @@ export type EwynOptions = EwynOptionsBase & {
|
|
|
125
123
|
/** Template configuration for name-based sending and validation */
|
|
126
124
|
templates?: TemplateConfig;
|
|
127
125
|
};
|
|
126
|
+
/**
|
|
127
|
+
* Configuration for the fetch-config CLI (ewyn.config.ts).
|
|
128
|
+
* Used only by the CLI to know which workspace/API key to use and where to write the generated file.
|
|
129
|
+
*/
|
|
130
|
+
export interface EwynFetchConfig {
|
|
131
|
+
/** Workspace ID (UUID) */
|
|
132
|
+
workspaceId: string;
|
|
133
|
+
/** API key secret (e.g. process.env.EWYN_API_KEY) */
|
|
134
|
+
apiKey: string;
|
|
135
|
+
/** Output path for the generated ewynTemplates file (e.g. ./src/ewynTemplates.ts). If omitted, defaults to ./ewynTemplates.ts in cwd. */
|
|
136
|
+
configurationPath?: string;
|
|
137
|
+
}
|
|
128
138
|
export {};
|
|
129
139
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CACxC;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;AAEjE;;GAEG;AACH,KAAK,YAAY,CAAC,CAAC,SAAS,mBAAmB,IAAI;KAChD,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,GAAG,CAAC,GAAG,KAAK;CAC5E,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAEnB;;GAEG;AACH,KAAK,YAAY,CAAC,CAAC,SAAS,mBAAmB,IAAI;KAChD,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,QAAQ,EAAE,KAAK,CAAA;KAAE,GAAG,CAAC,GAAG,KAAK;CAC7E,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAEnB;;GAEG;AACH,KAAK,mBAAmB,CAAC,CAAC,SAAS,mBAAmB,IACpD,YAAY,CAAC,CAAC,CAAC,SAAS,KAAK,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CACxC;AAED;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;AAEjE;;GAEG;AACH,KAAK,YAAY,CAAC,CAAC,SAAS,mBAAmB,IAAI;KAChD,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,GAAG,CAAC,GAAG,KAAK;CAC5E,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAEnB;;GAEG;AACH,KAAK,YAAY,CAAC,CAAC,SAAS,mBAAmB,IAAI;KAChD,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,QAAQ,EAAE,KAAK,CAAA;KAAE,GAAG,CAAC,GAAG,KAAK;CAC7E,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAEnB;;GAEG;AACH,KAAK,mBAAmB,CAAC,CAAC,SAAS,mBAAmB,IACpD,YAAY,CAAC,CAAC,CAAC,SAAS,KAAK,GAC3B;KAAG,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM;CAAE,GACnC;KAAG,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,GAAG,MAAM;CAAE,GAAG;KAAG,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM;CAAE,CAAC;AAE7E;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,MAAM,qBAAqB,CAC/B,OAAO,SAAS,cAAc,EAC9B,KAAK,SAAS,MAAM,OAAO,GAAG,MAAM,OAAO,IACzC;IACF,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,QAAQ,EAAE,KAAK,CAAC;IAChB,0DAA0D;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC;IACpC,mDAAmD;IACnD,SAAS,EAAE,mBAAmB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/C,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,QAAQ,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,0BAA0B;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,OAAO,SAAS,cAAc,IAAI,eAAe,GAAG;IAC/E,mDAAmD;IACnD,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG;IAC1C,mEAAmE;IACnE,SAAS,CAAC,EAAE,cAAc,CAAC;CAC5B,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,0BAA0B;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,yIAAyI;IACzI,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ewyn/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Official TypeScript SDK for Ewyn email service with full type safety",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
"types": "./dist/index.d.ts"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"ewyn": "./dist/cli.js"
|
|
16
|
+
},
|
|
14
17
|
"files": [
|
|
15
18
|
"dist"
|
|
16
19
|
],
|
|
@@ -35,7 +38,9 @@
|
|
|
35
38
|
"engines": {
|
|
36
39
|
"node": ">=18.0.0"
|
|
37
40
|
},
|
|
38
|
-
"dependencies": {
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"tsx": "^4.19.0"
|
|
43
|
+
},
|
|
39
44
|
"devDependencies": {
|
|
40
45
|
"@types/node": "^20.11.0",
|
|
41
46
|
"@workspace/eslint-config": "workspace:*",
|