@zeph-to/hook-sdk 0.1.1 → 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 +99 -50
- package/dist/cli.js +258 -46
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/zeph-hook.d.ts +5 -1
- package/dist/zeph-hook.d.ts.map +1 -1
- package/dist/zeph-hook.js +41 -12
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -1,39 +1,124 @@
|
|
|
1
|
-
# @zeph/hook-sdk
|
|
1
|
+
# @zeph-to/hook-sdk
|
|
2
2
|
|
|
3
3
|
Push notification SDK + CLI for [Zeph](https://zeph.to). Zero dependencies — uses native `fetch`.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @zeph/hook-sdk
|
|
8
|
+
npm install @zeph-to/hook-sdk
|
|
9
|
+
# or
|
|
10
|
+
npx @zeph-to/hook-sdk notify --title "Hello"
|
|
9
11
|
```
|
|
10
12
|
|
|
13
|
+
## CLI Usage
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Send a notification
|
|
17
|
+
zeph notify --title "Deploy done" --body "v2.1.0 shipped"
|
|
18
|
+
|
|
19
|
+
# Send with priority
|
|
20
|
+
zeph notify --title "Build failed" --priority high --url https://ci.example.com/123
|
|
21
|
+
|
|
22
|
+
# List recent pushes
|
|
23
|
+
zeph list
|
|
24
|
+
zeph list --limit 10 --type note
|
|
25
|
+
|
|
26
|
+
# Dismiss a push
|
|
27
|
+
zeph dismiss push_01JXY...
|
|
28
|
+
zeph dismiss --all
|
|
29
|
+
|
|
30
|
+
# Test connection
|
|
31
|
+
zeph test
|
|
32
|
+
|
|
33
|
+
# JSON output
|
|
34
|
+
zeph notify --title "Hello" --json
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Commands
|
|
38
|
+
|
|
39
|
+
| Command | Description |
|
|
40
|
+
|---------|-------------|
|
|
41
|
+
| `notify` | Send a push notification |
|
|
42
|
+
| `list` | List recent push notifications |
|
|
43
|
+
| `dismiss <id>` | Dismiss a push (or `--all`) |
|
|
44
|
+
| `test` | Send a test notification to verify setup |
|
|
45
|
+
|
|
46
|
+
### Notify Options
|
|
47
|
+
|
|
48
|
+
| Flag | Description |
|
|
49
|
+
|------|-------------|
|
|
50
|
+
| `--title <text>` | Push title |
|
|
51
|
+
| `--body <text>` | Push body |
|
|
52
|
+
| `--url <url>` | URL to include |
|
|
53
|
+
| `--type <type>` | Push type: `note`, `link`, `file` |
|
|
54
|
+
| `--priority <p>` | Priority: `low`, `normal`, `high`, `urgent` |
|
|
55
|
+
| `--device <id>` | Target device ID |
|
|
56
|
+
|
|
57
|
+
### List Options
|
|
58
|
+
|
|
59
|
+
| Flag | Description |
|
|
60
|
+
|------|-------------|
|
|
61
|
+
| `--limit <n>` | Number of pushes (1-20, default 5) |
|
|
62
|
+
| `--type <type>` | Filter by push type |
|
|
63
|
+
|
|
64
|
+
### Global Options
|
|
65
|
+
|
|
66
|
+
| Flag | Description |
|
|
67
|
+
|------|-------------|
|
|
68
|
+
| `--key <api-key>` | API key (or set `ZEPH_API_KEY` env) |
|
|
69
|
+
| `--base-url <url>` | API base URL (or set `ZEPH_BASE_URL` env) |
|
|
70
|
+
| `--json` | Output JSON format |
|
|
71
|
+
| `--version` | Print version |
|
|
72
|
+
|
|
73
|
+
### Exit Codes
|
|
74
|
+
|
|
75
|
+
| Code | Meaning |
|
|
76
|
+
|------|---------|
|
|
77
|
+
| 0 | Success |
|
|
78
|
+
| 1 | General error |
|
|
79
|
+
| 2 | Quota exceeded |
|
|
80
|
+
| 3 | Authentication failed |
|
|
81
|
+
|
|
82
|
+
### Environment Variables
|
|
83
|
+
|
|
84
|
+
| Variable | Description |
|
|
85
|
+
|----------|-------------|
|
|
86
|
+
| `ZEPH_API_KEY` | API key (fallback when `--key` not provided) |
|
|
87
|
+
| `ZEPH_BASE_URL` | API base URL (default: `https://api.zeph.to/v1`) |
|
|
88
|
+
|
|
11
89
|
## SDK Usage
|
|
12
90
|
|
|
13
91
|
```typescript
|
|
14
|
-
import { ZephHook } from '@zeph/hook-sdk';
|
|
92
|
+
import { ZephHook } from '@zeph-to/hook-sdk';
|
|
15
93
|
|
|
16
94
|
const hook = new ZephHook({ apiKey: 'ak_...' });
|
|
17
95
|
|
|
96
|
+
// Notify
|
|
18
97
|
const result = await hook.notify({
|
|
19
98
|
title: 'Build Complete',
|
|
20
99
|
body: 'Deploy succeeded',
|
|
21
100
|
url: 'https://example.com/deploy/123',
|
|
101
|
+
priority: 'high',
|
|
22
102
|
});
|
|
23
|
-
|
|
24
103
|
console.log(result.pushId); // 'push_01JXY...'
|
|
25
|
-
```
|
|
26
104
|
|
|
27
|
-
|
|
105
|
+
// List
|
|
106
|
+
const list = await hook.list({ limit: 5 });
|
|
107
|
+
console.log(list.pushes);
|
|
28
108
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
baseUrl: 'https://...', // Optional — API base URL (default: https://api.zeph.to)
|
|
33
|
-
timeout: 30000, // Optional — request timeout in ms (default: 30000)
|
|
34
|
-
});
|
|
109
|
+
// Dismiss
|
|
110
|
+
await hook.dismiss('push_01JXY...');
|
|
111
|
+
await hook.dismissAll();
|
|
35
112
|
```
|
|
36
113
|
|
|
114
|
+
### Constructor Options
|
|
115
|
+
|
|
116
|
+
| Field | Type | Description |
|
|
117
|
+
|-------|------|-------------|
|
|
118
|
+
| `apiKey` | `string` | Required — API key from Zeph settings |
|
|
119
|
+
| `baseUrl` | `string?` | API base URL (default: `https://api.zeph.to/v1`) |
|
|
120
|
+
| `timeout` | `number?` | Request timeout in ms (default: 30000) |
|
|
121
|
+
|
|
37
122
|
### Notify Payload
|
|
38
123
|
|
|
39
124
|
| Field | Type | Description |
|
|
@@ -42,12 +127,13 @@ const hook = new ZephHook({
|
|
|
42
127
|
| `body` | `string?` | Push body |
|
|
43
128
|
| `url` | `string?` | URL to include |
|
|
44
129
|
| `type` | `'note' \| 'link' \| 'file'?` | Push type (default: `note`) |
|
|
130
|
+
| `priority` | `'low' \| 'normal' \| 'high' \| 'urgent'?` | Priority (default: `normal`) |
|
|
45
131
|
| `targetDeviceId` | `string?` | Send to specific device |
|
|
46
132
|
|
|
47
133
|
### Error Handling
|
|
48
134
|
|
|
49
135
|
```typescript
|
|
50
|
-
import { ZephHook, AuthenticationError, QuotaExceededError, ZephError } from '@zeph/hook-sdk';
|
|
136
|
+
import { ZephHook, AuthenticationError, QuotaExceededError, ZephError } from '@zeph-to/hook-sdk';
|
|
51
137
|
|
|
52
138
|
try {
|
|
53
139
|
await hook.notify({ title: 'Hello' });
|
|
@@ -58,43 +144,6 @@ try {
|
|
|
58
144
|
}
|
|
59
145
|
```
|
|
60
146
|
|
|
61
|
-
## CLI Usage
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
# With API key flag
|
|
65
|
-
zeph notify --key ak_... --title "Deploy done" --body "v2.1.0 shipped"
|
|
66
|
-
|
|
67
|
-
# With environment variable
|
|
68
|
-
export ZEPH_API_KEY=ak_...
|
|
69
|
-
zeph notify --title "Build failed" --url https://ci.example.com/123
|
|
70
|
-
|
|
71
|
-
# JSON output
|
|
72
|
-
zeph notify --title "Hello" --json
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### CLI Options
|
|
76
|
-
|
|
77
|
-
| Flag | Description |
|
|
78
|
-
|------|-------------|
|
|
79
|
-
| `--key <api-key>` | API key (or set `ZEPH_API_KEY` env) |
|
|
80
|
-
| `--title <text>` | Push title |
|
|
81
|
-
| `--body <text>` | Push body |
|
|
82
|
-
| `--url <url>` | URL to include |
|
|
83
|
-
| `--type <type>` | Push type: `note`, `link`, `file` |
|
|
84
|
-
| `--device <id>` | Target device ID |
|
|
85
|
-
| `--base-url <url>` | API base URL |
|
|
86
|
-
| `--json` | Output JSON format |
|
|
87
|
-
| `--version` | Print version |
|
|
88
|
-
|
|
89
|
-
### Exit Codes
|
|
90
|
-
|
|
91
|
-
| Code | Meaning |
|
|
92
|
-
|------|---------|
|
|
93
|
-
| 0 | Success |
|
|
94
|
-
| 1 | General error |
|
|
95
|
-
| 2 | Quota exceeded |
|
|
96
|
-
| 3 | Authentication failed |
|
|
97
|
-
|
|
98
147
|
## Requirements
|
|
99
148
|
|
|
100
149
|
- Node.js >= 18 (uses native `fetch`)
|
package/dist/cli.js
CHANGED
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
5
|
const path_1 = require("path");
|
|
6
|
+
const readline_1 = require("readline");
|
|
6
7
|
const zeph_hook_js_1 = require("./zeph-hook.js");
|
|
7
8
|
const errors_js_1 = require("./errors.js");
|
|
8
|
-
const
|
|
9
|
+
const CONFIG_DIR = (0, path_1.join)(process.env.HOME ?? '~', '.zeph');
|
|
10
|
+
const CONFIG_FILE = (0, path_1.join)(CONFIG_DIR, 'config.json');
|
|
11
|
+
const VERSION = (() => {
|
|
9
12
|
try {
|
|
10
13
|
const pkg = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '..', 'package.json'), 'utf-8'));
|
|
11
14
|
return pkg.version;
|
|
@@ -13,16 +16,16 @@ const getVersion = () => {
|
|
|
13
16
|
catch {
|
|
14
17
|
return '0.0.0';
|
|
15
18
|
}
|
|
16
|
-
};
|
|
19
|
+
})();
|
|
17
20
|
// ── Arg Parser ──────────────────────────────────────────────────
|
|
18
21
|
const parseArgs = (argv) => {
|
|
19
22
|
const result = {};
|
|
23
|
+
const positional = [];
|
|
20
24
|
const args = argv.slice(2);
|
|
21
25
|
for (let i = 0; i < args.length; i++) {
|
|
22
26
|
const arg = args[i];
|
|
23
27
|
if (!arg.startsWith('--')) {
|
|
24
|
-
|
|
25
|
-
result._command = arg;
|
|
28
|
+
positional.push(arg);
|
|
26
29
|
continue;
|
|
27
30
|
}
|
|
28
31
|
const key = arg.slice(2);
|
|
@@ -35,21 +38,41 @@ const parseArgs = (argv) => {
|
|
|
35
38
|
i++;
|
|
36
39
|
}
|
|
37
40
|
}
|
|
41
|
+
result._command = positional[0] ?? '';
|
|
42
|
+
result._arg1 = positional[1] ?? '';
|
|
38
43
|
return result;
|
|
39
44
|
};
|
|
40
45
|
// ── Output ──────────────────────────────────────────────────────
|
|
41
46
|
const printUsage = () => {
|
|
42
|
-
console.log(`Usage: zeph
|
|
47
|
+
console.log(`Usage: zeph <command> [options]
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
Commands:
|
|
50
|
+
setup Interactive configuration (API key, Hook ID)
|
|
51
|
+
notify Send a push notification
|
|
52
|
+
list List recent push notifications
|
|
53
|
+
dismiss <id> Dismiss a push notification (or --all)
|
|
54
|
+
test Send a test notification to verify setup
|
|
55
|
+
|
|
56
|
+
Notify options:
|
|
46
57
|
--title <text> Push title
|
|
47
58
|
--body <text> Push body
|
|
48
59
|
--url <url> URL to include
|
|
49
60
|
--type <type> Push type (note|link|file) [default: note]
|
|
61
|
+
--priority <p> Priority (low|normal|high|urgent) [default: normal]
|
|
50
62
|
--device <id> Target device ID
|
|
51
|
-
|
|
63
|
+
|
|
64
|
+
List options:
|
|
65
|
+
--limit <n> Number of pushes (1-20, default 5)
|
|
66
|
+
--type <type> Filter by push type
|
|
67
|
+
|
|
68
|
+
Dismiss options:
|
|
69
|
+
--all Dismiss all notifications
|
|
70
|
+
|
|
71
|
+
Global options:
|
|
72
|
+
--key <api-key> API key (or set ZEPH_API_KEY env)
|
|
73
|
+
--base-url <url> API base URL (or set ZEPH_BASE_URL env)
|
|
52
74
|
--json Output JSON format
|
|
75
|
+
--version Show version
|
|
53
76
|
|
|
54
77
|
Environment:
|
|
55
78
|
ZEPH_API_KEY API key (fallback when --key not provided)
|
|
@@ -63,68 +86,257 @@ const printError = (message, isJson) => {
|
|
|
63
86
|
console.error(`Error: ${message}`);
|
|
64
87
|
}
|
|
65
88
|
};
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
89
|
+
const printJson = (data) => {
|
|
90
|
+
console.log(JSON.stringify(data, null, 2));
|
|
91
|
+
};
|
|
92
|
+
const loadConfig = () => {
|
|
93
|
+
try {
|
|
94
|
+
return JSON.parse((0, fs_1.readFileSync)(CONFIG_FILE, 'utf-8'));
|
|
69
95
|
}
|
|
70
|
-
|
|
71
|
-
|
|
96
|
+
catch {
|
|
97
|
+
return {};
|
|
72
98
|
}
|
|
73
99
|
};
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
100
|
+
const saveConfig = (config) => {
|
|
101
|
+
(0, fs_1.mkdirSync)(CONFIG_DIR, { recursive: true });
|
|
102
|
+
(0, fs_1.writeFileSync)(CONFIG_FILE, JSON.stringify(config, null, 2) + '\n');
|
|
103
|
+
};
|
|
104
|
+
const prompt = (question) => {
|
|
105
|
+
const rl = (0, readline_1.createInterface)({ input: process.stdin, output: process.stdout });
|
|
106
|
+
return new Promise((resolve) => {
|
|
107
|
+
rl.question(question, (answer) => {
|
|
108
|
+
rl.close();
|
|
109
|
+
resolve(answer.trim());
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
// ── Commands ────────────────────────────────────────────────────
|
|
114
|
+
const createHook = (args) => {
|
|
115
|
+
const config = loadConfig();
|
|
116
|
+
const apiKey = args.key || process.env.ZEPH_API_KEY || config.apiKey;
|
|
78
117
|
const isJson = args.json === true;
|
|
79
|
-
if (args.version === true) {
|
|
80
|
-
console.log(getVersion());
|
|
81
|
-
return 0;
|
|
82
|
-
}
|
|
83
|
-
if (!command || command === 'help') {
|
|
84
|
-
printUsage();
|
|
85
|
-
return 0;
|
|
86
|
-
}
|
|
87
|
-
if (command !== 'notify') {
|
|
88
|
-
printError(`Unknown command: ${command}`, isJson);
|
|
89
|
-
printUsage();
|
|
90
|
-
return 1;
|
|
91
|
-
}
|
|
92
|
-
const apiKey = args.key || process.env.ZEPH_API_KEY;
|
|
93
118
|
if (!apiKey) {
|
|
94
|
-
printError('API key required.
|
|
95
|
-
return
|
|
119
|
+
printError('API key required. Run "zeph setup" or set ZEPH_API_KEY', isJson);
|
|
120
|
+
return null;
|
|
96
121
|
}
|
|
97
|
-
const baseUrl = args['base-url'] || process.env.ZEPH_BASE_URL;
|
|
98
|
-
|
|
122
|
+
const baseUrl = args['base-url'] || process.env.ZEPH_BASE_URL || config.baseUrl;
|
|
123
|
+
return new zeph_hook_js_1.ZephHook({
|
|
99
124
|
apiKey,
|
|
100
125
|
...(baseUrl && { baseUrl }),
|
|
101
126
|
});
|
|
127
|
+
};
|
|
128
|
+
const handleNotify = async (args) => {
|
|
129
|
+
const isJson = args.json === true;
|
|
130
|
+
const hook = createHook(args);
|
|
131
|
+
if (!hook)
|
|
132
|
+
return 3;
|
|
102
133
|
try {
|
|
103
134
|
const result = await hook.notify({
|
|
104
135
|
title: args.title,
|
|
105
136
|
body: args.body,
|
|
106
137
|
url: args.url,
|
|
107
138
|
type: args.type || undefined,
|
|
139
|
+
priority: args.priority || undefined,
|
|
108
140
|
targetDeviceId: args.device,
|
|
109
141
|
});
|
|
110
|
-
|
|
142
|
+
if (isJson) {
|
|
143
|
+
printJson({ pushId: result.pushId, status: 'ok' });
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
console.log(`Push sent: ${result.pushId}`);
|
|
147
|
+
}
|
|
111
148
|
return 0;
|
|
112
149
|
}
|
|
113
150
|
catch (err) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
151
|
+
return handleError(err, isJson);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const handleList = async (args) => {
|
|
155
|
+
const isJson = args.json === true;
|
|
156
|
+
const hook = createHook(args);
|
|
157
|
+
if (!hook)
|
|
158
|
+
return 3;
|
|
159
|
+
try {
|
|
160
|
+
const limit = args.limit ? Number(args.limit) : undefined;
|
|
161
|
+
const result = await hook.list({
|
|
162
|
+
limit,
|
|
163
|
+
type: args.type,
|
|
164
|
+
});
|
|
165
|
+
if (isJson) {
|
|
166
|
+
printJson(result);
|
|
117
167
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
168
|
+
else {
|
|
169
|
+
if (result.pushes.length === 0) {
|
|
170
|
+
console.log('No pushes found.');
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
for (const p of result.pushes) {
|
|
174
|
+
const title = p.title ?? '(no title)';
|
|
175
|
+
const time = new Date(p.createdAt).toLocaleString();
|
|
176
|
+
console.log(` ${p.pushId} [${p.type}] ${title} (${time})`);
|
|
177
|
+
}
|
|
178
|
+
if (result.hasMore)
|
|
179
|
+
console.log(` ... more available (use --limit to increase)`);
|
|
180
|
+
}
|
|
121
181
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
return handleError(err, isJson);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
const handleDismiss = async (args) => {
|
|
189
|
+
const isJson = args.json === true;
|
|
190
|
+
const hook = createHook(args);
|
|
191
|
+
if (!hook)
|
|
192
|
+
return 3;
|
|
193
|
+
try {
|
|
194
|
+
if (args.all === true) {
|
|
195
|
+
const result = await hook.dismissAll();
|
|
196
|
+
if (isJson) {
|
|
197
|
+
printJson({ dismissed: result.dismissed, status: 'ok' });
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
console.log(`Dismissed ${result.dismissed} pushes.`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const pushId = args._arg1;
|
|
205
|
+
if (!pushId) {
|
|
206
|
+
printError('Push ID required. Usage: zeph dismiss <push-id> or zeph dismiss --all', isJson);
|
|
207
|
+
return 1;
|
|
208
|
+
}
|
|
209
|
+
await hook.dismiss(pushId);
|
|
210
|
+
if (isJson) {
|
|
211
|
+
printJson({ dismissed: true, pushId, status: 'ok' });
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
console.log(`Dismissed: ${pushId}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return 0;
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
return handleError(err, isJson);
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const handleTest = async (args) => {
|
|
224
|
+
const isJson = args.json === true;
|
|
225
|
+
const hook = createHook(args);
|
|
226
|
+
if (!hook)
|
|
227
|
+
return 3;
|
|
228
|
+
try {
|
|
229
|
+
const result = await hook.notify({
|
|
230
|
+
title: 'Zeph Test',
|
|
231
|
+
body: `CLI connected successfully (v${VERSION})`,
|
|
232
|
+
});
|
|
233
|
+
if (isJson) {
|
|
234
|
+
printJson({ pushId: result.pushId, status: 'ok', message: 'Test notification sent' });
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
console.log(`Test notification sent: ${result.pushId}`);
|
|
125
238
|
}
|
|
126
|
-
|
|
239
|
+
return 0;
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
return handleError(err, isJson);
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
const handleSetup = async () => {
|
|
246
|
+
console.log('\n Zeph Setup\n');
|
|
247
|
+
const existing = loadConfig();
|
|
248
|
+
// API Key
|
|
249
|
+
const currentKey = process.env.ZEPH_API_KEY || existing.apiKey;
|
|
250
|
+
if (currentKey) {
|
|
251
|
+
console.log(` API Key: ${currentKey.slice(0, 12)}... (already set)`);
|
|
252
|
+
}
|
|
253
|
+
const keyInput = await prompt(currentKey
|
|
254
|
+
? ' New API Key (Enter to keep current): '
|
|
255
|
+
: ' API Key (from Settings > API Keys): ');
|
|
256
|
+
const apiKey = keyInput || currentKey;
|
|
257
|
+
if (!apiKey) {
|
|
258
|
+
console.error('\n Error: API key is required.');
|
|
127
259
|
return 1;
|
|
128
260
|
}
|
|
261
|
+
// Hook ID
|
|
262
|
+
const currentHook = process.env.ZEPH_HOOK_ID || existing.hookId;
|
|
263
|
+
if (currentHook) {
|
|
264
|
+
console.log(` Hook ID: ${currentHook} (already set)`);
|
|
265
|
+
}
|
|
266
|
+
const hookInput = await prompt(currentHook
|
|
267
|
+
? ' New Hook ID (Enter to keep, "none" to remove): '
|
|
268
|
+
: ' Hook ID (optional, for prompt/input): ');
|
|
269
|
+
const hookId = hookInput === 'none' ? undefined : (hookInput || currentHook);
|
|
270
|
+
// Base URL
|
|
271
|
+
const currentUrl = process.env.ZEPH_BASE_URL || existing.baseUrl;
|
|
272
|
+
const urlInput = await prompt(` Base URL (Enter for ${currentUrl || 'https://api.zeph.to/v1'}): `);
|
|
273
|
+
const baseUrl = urlInput || currentUrl;
|
|
274
|
+
// Save config
|
|
275
|
+
const config = { apiKey, ...(hookId && { hookId }), ...(baseUrl && { baseUrl }) };
|
|
276
|
+
saveConfig(config);
|
|
277
|
+
console.log(`\n Config saved to ${CONFIG_FILE}`);
|
|
278
|
+
// Test connection
|
|
279
|
+
console.log(' Testing connection...');
|
|
280
|
+
try {
|
|
281
|
+
const hook = new zeph_hook_js_1.ZephHook({ apiKey, ...(baseUrl && { baseUrl }) });
|
|
282
|
+
const result = await hook.notify({
|
|
283
|
+
title: 'Zeph Setup',
|
|
284
|
+
body: `CLI configured successfully (v${VERSION})`,
|
|
285
|
+
});
|
|
286
|
+
console.log(` Test push sent: ${result.pushId}`);
|
|
287
|
+
}
|
|
288
|
+
catch (err) {
|
|
289
|
+
console.error(` Test failed: ${err instanceof Error ? err.message : 'Unknown error'}`);
|
|
290
|
+
console.error(' Config saved but connection failed. Check your API key.');
|
|
291
|
+
return 1;
|
|
292
|
+
}
|
|
293
|
+
console.log('\n Done! Restart Claude Code to apply.\n');
|
|
294
|
+
return 0;
|
|
295
|
+
};
|
|
296
|
+
// ── Error Handler ───────────────────────────────────────────────
|
|
297
|
+
const handleError = (err, isJson) => {
|
|
298
|
+
if (err instanceof errors_js_1.QuotaExceededError) {
|
|
299
|
+
printError(err.message, isJson);
|
|
300
|
+
return 2;
|
|
301
|
+
}
|
|
302
|
+
if (err instanceof errors_js_1.AuthenticationError) {
|
|
303
|
+
printError(err.message, isJson);
|
|
304
|
+
return 3;
|
|
305
|
+
}
|
|
306
|
+
if (err instanceof errors_js_1.ZephError) {
|
|
307
|
+
printError(err.message, isJson);
|
|
308
|
+
return 1;
|
|
309
|
+
}
|
|
310
|
+
printError(err instanceof Error ? err.message : 'Unknown error', isJson);
|
|
311
|
+
return 1;
|
|
312
|
+
};
|
|
313
|
+
// ── Main ────────────────────────────────────────────────────────
|
|
314
|
+
const main = async () => {
|
|
315
|
+
const args = parseArgs(process.argv);
|
|
316
|
+
const command = args._command;
|
|
317
|
+
if (args.version === true) {
|
|
318
|
+
console.log(VERSION);
|
|
319
|
+
return 0;
|
|
320
|
+
}
|
|
321
|
+
if (!command || command === 'help') {
|
|
322
|
+
printUsage();
|
|
323
|
+
return 0;
|
|
324
|
+
}
|
|
325
|
+
switch (command) {
|
|
326
|
+
case 'setup':
|
|
327
|
+
return handleSetup();
|
|
328
|
+
case 'notify':
|
|
329
|
+
return handleNotify(args);
|
|
330
|
+
case 'list':
|
|
331
|
+
return handleList(args);
|
|
332
|
+
case 'dismiss':
|
|
333
|
+
return handleDismiss(args);
|
|
334
|
+
case 'test':
|
|
335
|
+
return handleTest(args);
|
|
336
|
+
default:
|
|
337
|
+
printError(`Unknown command: ${command}`, args.json === true);
|
|
338
|
+
printUsage();
|
|
339
|
+
return 1;
|
|
340
|
+
}
|
|
129
341
|
};
|
|
130
342
|
main().then((code) => process.exit(code));
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { ZephHook } from './zeph-hook.js';
|
|
2
2
|
export { ZephError, AuthenticationError, QuotaExceededError } from './errors.js';
|
|
3
|
-
export type { ZephOptions, NotifyPayload, NotifyResult } from './types.js';
|
|
3
|
+
export type { ZephOptions, NotifyPayload, NotifyResult, ListParams, ListResult, DismissOneResult, DismissAllResult, PushItem } from './types.js';
|
|
4
4
|
//# 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":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjF,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjF,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -8,11 +8,34 @@ export interface NotifyPayload {
|
|
|
8
8
|
body?: string;
|
|
9
9
|
url?: string;
|
|
10
10
|
type?: 'note' | 'link' | 'file';
|
|
11
|
+
priority?: 'low' | 'normal' | 'high' | 'urgent';
|
|
11
12
|
targetDeviceId?: string;
|
|
12
13
|
}
|
|
13
14
|
export interface NotifyResult {
|
|
14
15
|
pushId: string;
|
|
15
16
|
}
|
|
17
|
+
export interface ListParams {
|
|
18
|
+
limit?: number;
|
|
19
|
+
type?: 'note' | 'link' | 'file' | 'clipboard' | 'hook';
|
|
20
|
+
}
|
|
21
|
+
export interface PushItem {
|
|
22
|
+
pushId: string;
|
|
23
|
+
type: string;
|
|
24
|
+
title?: string;
|
|
25
|
+
body?: string;
|
|
26
|
+
createdAt: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ListResult {
|
|
29
|
+
pushes: PushItem[];
|
|
30
|
+
count: number;
|
|
31
|
+
hasMore: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface DismissOneResult {
|
|
34
|
+
dismissed: true;
|
|
35
|
+
}
|
|
36
|
+
export interface DismissAllResult {
|
|
37
|
+
dismissed: number;
|
|
38
|
+
}
|
|
16
39
|
export interface ApiErrorResponse {
|
|
17
40
|
error: {
|
|
18
41
|
code: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAChC,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;CACxD;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH"}
|
package/dist/zeph-hook.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import type { ZephOptions, NotifyPayload, NotifyResult } from './types.js';
|
|
1
|
+
import type { ZephOptions, NotifyPayload, NotifyResult, ListParams, ListResult, DismissOneResult, DismissAllResult } from './types.js';
|
|
2
2
|
export declare class ZephHook {
|
|
3
3
|
private readonly apiKey;
|
|
4
4
|
private readonly baseUrl;
|
|
5
5
|
private readonly timeoutMs;
|
|
6
6
|
constructor(options: ZephOptions);
|
|
7
7
|
notify(payload: NotifyPayload): Promise<NotifyResult>;
|
|
8
|
+
list(params?: ListParams): Promise<ListResult>;
|
|
9
|
+
dismiss(pushId: string): Promise<DismissOneResult>;
|
|
10
|
+
dismissAll(): Promise<DismissAllResult>;
|
|
11
|
+
private request;
|
|
8
12
|
private parseError;
|
|
9
13
|
}
|
|
10
14
|
//# sourceMappingURL=zeph-hook.d.ts.map
|
package/dist/zeph-hook.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zeph-hook.d.ts","sourceRoot":"","sources":["../src/zeph-hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAoB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"zeph-hook.d.ts","sourceRoot":"","sources":["../src/zeph-hook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAY,gBAAgB,EAAE,gBAAgB,EAAoB,MAAM,YAAY,CAAC;AAMnK,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,OAAO,EAAE,WAAW;IAS1B,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IASrD,IAAI,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAmB9C,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAKlD,UAAU,IAAI,OAAO,CAAC,gBAAgB,CAAC;YAK/B,OAAO;IAiCrB,OAAO,CAAC,UAAU;CASnB"}
|
package/dist/zeph-hook.js
CHANGED
|
@@ -17,17 +17,50 @@ class ZephHook {
|
|
|
17
17
|
this.timeoutMs = options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
18
18
|
}
|
|
19
19
|
async notify(payload) {
|
|
20
|
+
const json = await this.request('POST', '/pushes/send', payload);
|
|
21
|
+
const pushId = json.data?.pushId;
|
|
22
|
+
if (!pushId) {
|
|
23
|
+
throw new errors_js_1.ZephError('Server returned no pushId', 'INVALID_RESPONSE', 500);
|
|
24
|
+
}
|
|
25
|
+
return { pushId };
|
|
26
|
+
}
|
|
27
|
+
async list(params) {
|
|
28
|
+
const query = new URLSearchParams();
|
|
29
|
+
if (params?.limit)
|
|
30
|
+
query.set('limit', String(params.limit));
|
|
31
|
+
if (params?.type)
|
|
32
|
+
query.set('type', params.type);
|
|
33
|
+
const qs = query.toString();
|
|
34
|
+
const json = await this.request('GET', `/pushes${qs ? `?${qs}` : ''}`);
|
|
35
|
+
const pushes = json.data.map((p) => ({
|
|
36
|
+
pushId: p.pushId,
|
|
37
|
+
type: p.type,
|
|
38
|
+
title: p.title,
|
|
39
|
+
body: p.body?.slice(0, 100),
|
|
40
|
+
createdAt: p.createdAt,
|
|
41
|
+
}));
|
|
42
|
+
return { pushes, count: pushes.length, hasMore: json.pagination?.hasMore ?? false };
|
|
43
|
+
}
|
|
44
|
+
async dismiss(pushId) {
|
|
45
|
+
await this.request('POST', `/pushes/${encodeURIComponent(pushId)}/dismiss`);
|
|
46
|
+
return { dismissed: true };
|
|
47
|
+
}
|
|
48
|
+
async dismissAll() {
|
|
49
|
+
const json = await this.request('POST', '/pushes/dismiss-all');
|
|
50
|
+
return { dismissed: json.data?.dismissed ?? 0 };
|
|
51
|
+
}
|
|
52
|
+
async request(method, path, body) {
|
|
20
53
|
const controller = new AbortController();
|
|
21
54
|
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
55
|
+
const headers = { 'X-API-Key': this.apiKey };
|
|
56
|
+
if (body)
|
|
57
|
+
headers['Content-Type'] = 'application/json';
|
|
22
58
|
let response;
|
|
23
59
|
try {
|
|
24
|
-
response = await fetch(`${this.baseUrl}
|
|
25
|
-
method
|
|
26
|
-
headers
|
|
27
|
-
|
|
28
|
-
'X-API-Key': this.apiKey,
|
|
29
|
-
},
|
|
30
|
-
body: JSON.stringify(payload),
|
|
60
|
+
response = await fetch(`${this.baseUrl}${path}`, {
|
|
61
|
+
method,
|
|
62
|
+
headers,
|
|
63
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
31
64
|
signal: controller.signal,
|
|
32
65
|
});
|
|
33
66
|
}
|
|
@@ -44,11 +77,7 @@ class ZephHook {
|
|
|
44
77
|
if (!response.ok) {
|
|
45
78
|
throw this.parseError(response.status, json);
|
|
46
79
|
}
|
|
47
|
-
|
|
48
|
-
if (!pushId) {
|
|
49
|
-
throw new errors_js_1.ZephError('Server returned no pushId', 'INVALID_RESPONSE', response.status);
|
|
50
|
-
}
|
|
51
|
-
return { pushId };
|
|
80
|
+
return json;
|
|
52
81
|
}
|
|
53
82
|
parseError(status, body) {
|
|
54
83
|
const message = body.error?.message ?? `Request failed with status ${status}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeph-to/hook-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Zeph push notification SDK + CLI — zero dependencies",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -35,7 +35,11 @@
|
|
|
35
35
|
"push",
|
|
36
36
|
"notification",
|
|
37
37
|
"cli",
|
|
38
|
-
"webhook"
|
|
38
|
+
"webhook",
|
|
39
|
+
"ai-agent",
|
|
40
|
+
"mcp",
|
|
41
|
+
"claude",
|
|
42
|
+
"devtools"
|
|
39
43
|
],
|
|
40
44
|
"license": "MIT"
|
|
41
45
|
}
|