@goliapkg/sentori-cli 0.5.2 → 0.6.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 +51 -0
- package/lib/index.js +314 -3
- package/lib/index.js.map +1 -1
- package/lib/mcp.d.ts +14 -0
- package/lib/mcp.d.ts.map +1 -0
- package/lib/mcp.js +371 -0
- package/lib/mcp.js.map +1 -0
- package/lib/push.d.ts +42 -0
- package/lib/push.d.ts.map +1 -0
- package/lib/push.js +92 -0
- package/lib/push.js.map +1 -0
- package/lib/source-bundle.d.ts +28 -0
- package/lib/source-bundle.d.ts.map +1 -0
- package/lib/source-bundle.js +193 -0
- package/lib/source-bundle.js.map +1 -0
- package/lib/upload.d.ts +1 -1
- package/lib/upload.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/__tests__/mcp.test.ts +124 -0
- package/src/__tests__/source-bundle-from-dir.test.ts +85 -0
- package/src/__tests__/source-bundle.test.ts +105 -0
- package/src/index.ts +306 -3
- package/src/mcp.ts +399 -0
- package/src/push.ts +174 -0
- package/src/source-bundle.ts +234 -0
- package/src/upload.ts +1 -1
package/lib/mcp.js
ADDED
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
// v1.2 W9 — Sentori MCP server.
|
|
2
|
+
//
|
|
3
|
+
// Stdio JSON-RPC 2.0 transport per the Model Context Protocol spec
|
|
4
|
+
// (https://modelcontextprotocol.io/). LLM clients (Claude Code,
|
|
5
|
+
// custom agents) spawn `sentori-cli mcp serve` as a subprocess and
|
|
6
|
+
// pipe MCP messages over stdin/stdout. Each tool call translates
|
|
7
|
+
// 1:1 to the existing admin API; the MCP layer is pure protocol
|
|
8
|
+
// glue + auth-passthrough.
|
|
9
|
+
//
|
|
10
|
+
// Why CLI-hosted instead of server-hosted MCP:
|
|
11
|
+
// - The Sentori server exposes admin endpoints over HTTPS already;
|
|
12
|
+
// spinning up a parallel MCP endpoint would duplicate auth +
|
|
13
|
+
// route boilerplate.
|
|
14
|
+
// - LLM clients expect MCP servers to be local stdio subprocesses
|
|
15
|
+
// (Claude Code config, gptme, etc.). The CLI is the natural
|
|
16
|
+
// binary to embed it in — the operator already has it installed
|
|
17
|
+
// and a token configured.
|
|
18
|
+
// - Easier to ship + version with the rest of the CLI.
|
|
19
|
+
import { createInterface } from 'node:readline';
|
|
20
|
+
/** Run the MCP server over stdio. Returns when stdin closes. */
|
|
21
|
+
export async function runMcpServer(ctx) {
|
|
22
|
+
const tools = buildTools();
|
|
23
|
+
const toolMap = new Map(tools.map((t) => [t.name, t]));
|
|
24
|
+
const rl = createInterface({ input: process.stdin });
|
|
25
|
+
for await (const line of rl) {
|
|
26
|
+
const trimmed = line.trim();
|
|
27
|
+
if (!trimmed)
|
|
28
|
+
continue;
|
|
29
|
+
let req;
|
|
30
|
+
try {
|
|
31
|
+
req = JSON.parse(trimmed);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// Per spec, malformed requests get a parse-error response with
|
|
35
|
+
// null id.
|
|
36
|
+
send({
|
|
37
|
+
error: { code: -32700, message: 'Parse error' },
|
|
38
|
+
id: null,
|
|
39
|
+
jsonrpc: '2.0',
|
|
40
|
+
});
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// Notifications (no `id`) get no response.
|
|
44
|
+
const isNotification = req.id === undefined || req.id === null;
|
|
45
|
+
try {
|
|
46
|
+
const result = await dispatch(req, toolMap, ctx, tools);
|
|
47
|
+
if (!isNotification) {
|
|
48
|
+
send({ id: req.id ?? null, jsonrpc: '2.0', result });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
if (!isNotification) {
|
|
53
|
+
send({
|
|
54
|
+
error: { code: -32603, message: e.message },
|
|
55
|
+
id: req.id ?? null,
|
|
56
|
+
jsonrpc: '2.0',
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function send(resp) {
|
|
63
|
+
process.stdout.write(JSON.stringify(resp) + '\n');
|
|
64
|
+
}
|
|
65
|
+
async function dispatch(req, toolMap, ctx, tools) {
|
|
66
|
+
switch (req.method) {
|
|
67
|
+
case 'initialize':
|
|
68
|
+
return {
|
|
69
|
+
capabilities: { tools: {} },
|
|
70
|
+
protocolVersion: '2024-11-05',
|
|
71
|
+
serverInfo: { name: 'sentori', version: '1.0' },
|
|
72
|
+
};
|
|
73
|
+
case 'notifications/initialized':
|
|
74
|
+
return {};
|
|
75
|
+
case 'tools/list':
|
|
76
|
+
return {
|
|
77
|
+
tools: tools.map((t) => ({
|
|
78
|
+
description: t.description,
|
|
79
|
+
inputSchema: t.inputSchema,
|
|
80
|
+
name: t.name,
|
|
81
|
+
})),
|
|
82
|
+
};
|
|
83
|
+
case 'tools/call': {
|
|
84
|
+
const params = (req.params ?? {});
|
|
85
|
+
const name = params.name;
|
|
86
|
+
if (typeof name !== 'string')
|
|
87
|
+
throw new Error('missing tools/call.name');
|
|
88
|
+
const tool = toolMap.get(name);
|
|
89
|
+
if (!tool)
|
|
90
|
+
throw new Error(`unknown tool: ${name}`);
|
|
91
|
+
const result = await tool.handler(params.arguments ?? {}, ctx);
|
|
92
|
+
return {
|
|
93
|
+
content: [
|
|
94
|
+
{
|
|
95
|
+
text: typeof result === 'string' ? result : JSON.stringify(result, null, 2),
|
|
96
|
+
type: 'text',
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
default:
|
|
102
|
+
throw new Error(`method not found: ${req.method}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// ── Tool implementations ─────────────────────────────────────────
|
|
106
|
+
async function adminGet(ctx, path) {
|
|
107
|
+
const url = `${ctx.apiUrl.replace(/\/+$/, '')}/admin/api${path}`;
|
|
108
|
+
const resp = await fetch(url, {
|
|
109
|
+
headers: { Authorization: `Bearer ${ctx.token}` },
|
|
110
|
+
});
|
|
111
|
+
if (!resp.ok)
|
|
112
|
+
throw new Error(`GET ${path} → ${resp.status} ${resp.statusText}`);
|
|
113
|
+
return (await resp.json());
|
|
114
|
+
}
|
|
115
|
+
async function adminPatch(ctx, path, body) {
|
|
116
|
+
const url = `${ctx.apiUrl.replace(/\/+$/, '')}/admin/api${path}`;
|
|
117
|
+
const resp = await fetch(url, {
|
|
118
|
+
body: JSON.stringify(body),
|
|
119
|
+
headers: {
|
|
120
|
+
Authorization: `Bearer ${ctx.token}`,
|
|
121
|
+
'Content-Type': 'application/json',
|
|
122
|
+
},
|
|
123
|
+
method: 'PATCH',
|
|
124
|
+
});
|
|
125
|
+
if (!resp.ok)
|
|
126
|
+
throw new Error(`PATCH ${path} → ${resp.status} ${resp.statusText}`);
|
|
127
|
+
return (await resp.json());
|
|
128
|
+
}
|
|
129
|
+
async function adminPost(ctx, path, body) {
|
|
130
|
+
const url = `${ctx.apiUrl.replace(/\/+$/, '')}/admin/api${path}`;
|
|
131
|
+
const resp = await fetch(url, {
|
|
132
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
133
|
+
headers: {
|
|
134
|
+
Authorization: `Bearer ${ctx.token}`,
|
|
135
|
+
'Content-Type': 'application/json',
|
|
136
|
+
},
|
|
137
|
+
method: 'POST',
|
|
138
|
+
});
|
|
139
|
+
if (!resp.ok)
|
|
140
|
+
throw new Error(`POST ${path} → ${resp.status} ${resp.statusText}`);
|
|
141
|
+
if (resp.status === 204)
|
|
142
|
+
return null;
|
|
143
|
+
return (await resp.json());
|
|
144
|
+
}
|
|
145
|
+
async function adminPut(ctx, path) {
|
|
146
|
+
const url = `${ctx.apiUrl.replace(/\/+$/, '')}/admin/api${path}`;
|
|
147
|
+
const resp = await fetch(url, {
|
|
148
|
+
headers: { Authorization: `Bearer ${ctx.token}` },
|
|
149
|
+
method: 'PUT',
|
|
150
|
+
});
|
|
151
|
+
if (!resp.ok)
|
|
152
|
+
throw new Error(`PUT ${path} → ${resp.status} ${resp.statusText}`);
|
|
153
|
+
if (resp.status === 204)
|
|
154
|
+
return null;
|
|
155
|
+
return (await resp.json());
|
|
156
|
+
}
|
|
157
|
+
async function adminDelete(ctx, path) {
|
|
158
|
+
const url = `${ctx.apiUrl.replace(/\/+$/, '')}/admin/api${path}`;
|
|
159
|
+
const resp = await fetch(url, {
|
|
160
|
+
headers: { Authorization: `Bearer ${ctx.token}` },
|
|
161
|
+
method: 'DELETE',
|
|
162
|
+
});
|
|
163
|
+
if (!resp.ok)
|
|
164
|
+
throw new Error(`DELETE ${path} → ${resp.status} ${resp.statusText}`);
|
|
165
|
+
if (resp.status === 204)
|
|
166
|
+
return null;
|
|
167
|
+
return (await resp.json());
|
|
168
|
+
}
|
|
169
|
+
function asString(v, name) {
|
|
170
|
+
if (typeof v !== 'string' || v.length === 0) {
|
|
171
|
+
throw new Error(`${name} is required (string)`);
|
|
172
|
+
}
|
|
173
|
+
return v;
|
|
174
|
+
}
|
|
175
|
+
function asOptionalString(v) {
|
|
176
|
+
if (v === undefined || v === null)
|
|
177
|
+
return undefined;
|
|
178
|
+
if (typeof v !== 'string')
|
|
179
|
+
throw new Error('expected string');
|
|
180
|
+
return v;
|
|
181
|
+
}
|
|
182
|
+
export function buildTools() {
|
|
183
|
+
return [
|
|
184
|
+
{
|
|
185
|
+
description: 'List issues for a Sentori project, with optional status / priority / label filters.',
|
|
186
|
+
handler: async (args, ctx) => {
|
|
187
|
+
const projectId = asString(args.projectId, 'projectId');
|
|
188
|
+
const usp = new URLSearchParams();
|
|
189
|
+
const status = asOptionalString(args.status) ?? 'any';
|
|
190
|
+
usp.set('status', status);
|
|
191
|
+
if (args.priority)
|
|
192
|
+
usp.set('priority', String(args.priority));
|
|
193
|
+
if (args.label)
|
|
194
|
+
usp.set('labels', String(args.label));
|
|
195
|
+
if (typeof args.limit === 'number')
|
|
196
|
+
usp.set('limit', String(args.limit));
|
|
197
|
+
return await adminGet(ctx, `/projects/${projectId}/issues?${usp}`);
|
|
198
|
+
},
|
|
199
|
+
inputSchema: {
|
|
200
|
+
properties: {
|
|
201
|
+
label: { type: 'string' },
|
|
202
|
+
limit: { type: 'number' },
|
|
203
|
+
priority: { type: 'string' },
|
|
204
|
+
projectId: { type: 'string' },
|
|
205
|
+
status: { type: 'string' },
|
|
206
|
+
},
|
|
207
|
+
required: ['projectId'],
|
|
208
|
+
type: 'object',
|
|
209
|
+
},
|
|
210
|
+
name: 'sentori_issue_list',
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
description: 'Get full detail for one Sentori issue including its activity feed.',
|
|
214
|
+
handler: async (args, ctx) => {
|
|
215
|
+
const projectId = asString(args.projectId, 'projectId');
|
|
216
|
+
const issueId = asString(args.issueId, 'issueId');
|
|
217
|
+
const [issue, activity] = await Promise.all([
|
|
218
|
+
adminGet(ctx, `/projects/${projectId}/issues/${issueId}`),
|
|
219
|
+
adminGet(ctx, `/projects/${projectId}/issues/${issueId}/activity`),
|
|
220
|
+
]);
|
|
221
|
+
return { activity, issue };
|
|
222
|
+
},
|
|
223
|
+
inputSchema: {
|
|
224
|
+
properties: {
|
|
225
|
+
issueId: { type: 'string' },
|
|
226
|
+
projectId: { type: 'string' },
|
|
227
|
+
},
|
|
228
|
+
required: ['projectId', 'issueId'],
|
|
229
|
+
type: 'object',
|
|
230
|
+
},
|
|
231
|
+
name: 'sentori_issue_get',
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
description: 'Add a comment to a Sentori issue.',
|
|
235
|
+
handler: async (args, ctx) => {
|
|
236
|
+
const projectId = asString(args.projectId, 'projectId');
|
|
237
|
+
const issueId = asString(args.issueId, 'issueId');
|
|
238
|
+
const body = asString(args.body, 'body');
|
|
239
|
+
return await adminPost(ctx, `/projects/${projectId}/issues/${issueId}/comments`, {
|
|
240
|
+
body,
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
inputSchema: {
|
|
244
|
+
properties: {
|
|
245
|
+
body: { type: 'string' },
|
|
246
|
+
issueId: { type: 'string' },
|
|
247
|
+
projectId: { type: 'string' },
|
|
248
|
+
},
|
|
249
|
+
required: ['projectId', 'issueId', 'body'],
|
|
250
|
+
type: 'object',
|
|
251
|
+
},
|
|
252
|
+
name: 'sentori_issue_comment',
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
description: 'Transition an issue to a new status (active|silenced|muted|resolved|closed).',
|
|
256
|
+
handler: async (args, ctx) => {
|
|
257
|
+
const projectId = asString(args.projectId, 'projectId');
|
|
258
|
+
const issueId = asString(args.issueId, 'issueId');
|
|
259
|
+
const status = asString(args.status, 'status');
|
|
260
|
+
return await adminPatch(ctx, `/projects/${projectId}/issues/${issueId}`, {
|
|
261
|
+
status,
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
inputSchema: {
|
|
265
|
+
properties: {
|
|
266
|
+
issueId: { type: 'string' },
|
|
267
|
+
projectId: { type: 'string' },
|
|
268
|
+
status: {
|
|
269
|
+
enum: ['active', 'silenced', 'muted', 'resolved', 'closed'],
|
|
270
|
+
type: 'string',
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
required: ['projectId', 'issueId', 'status'],
|
|
274
|
+
type: 'object',
|
|
275
|
+
},
|
|
276
|
+
name: 'sentori_issue_transition',
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
description: 'Assign an issue to a user, or pass userId=null to unassign.',
|
|
280
|
+
handler: async (args, ctx) => {
|
|
281
|
+
const projectId = asString(args.projectId, 'projectId');
|
|
282
|
+
const issueId = asString(args.issueId, 'issueId');
|
|
283
|
+
const userId = args.userId === null ? null : asOptionalString(args.userId);
|
|
284
|
+
return await adminPatch(ctx, `/projects/${projectId}/issues/${issueId}`, {
|
|
285
|
+
assigneeUserId: userId ?? null,
|
|
286
|
+
});
|
|
287
|
+
},
|
|
288
|
+
inputSchema: {
|
|
289
|
+
properties: {
|
|
290
|
+
issueId: { type: 'string' },
|
|
291
|
+
projectId: { type: 'string' },
|
|
292
|
+
userId: { type: ['string', 'null'] },
|
|
293
|
+
},
|
|
294
|
+
required: ['projectId', 'issueId', 'userId'],
|
|
295
|
+
type: 'object',
|
|
296
|
+
},
|
|
297
|
+
name: 'sentori_issue_assign',
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
description: 'Set the triage priority on an issue.',
|
|
301
|
+
handler: async (args, ctx) => {
|
|
302
|
+
const projectId = asString(args.projectId, 'projectId');
|
|
303
|
+
const issueId = asString(args.issueId, 'issueId');
|
|
304
|
+
const priority = asString(args.priority, 'priority');
|
|
305
|
+
return await adminPatch(ctx, `/projects/${projectId}/issues/${issueId}`, {
|
|
306
|
+
priority,
|
|
307
|
+
});
|
|
308
|
+
},
|
|
309
|
+
inputSchema: {
|
|
310
|
+
properties: {
|
|
311
|
+
issueId: { type: 'string' },
|
|
312
|
+
priority: { enum: ['p0', 'p1', 'p2', 'p3'], type: 'string' },
|
|
313
|
+
projectId: { type: 'string' },
|
|
314
|
+
},
|
|
315
|
+
required: ['projectId', 'issueId', 'priority'],
|
|
316
|
+
type: 'object',
|
|
317
|
+
},
|
|
318
|
+
name: 'sentori_issue_set_priority',
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
description: 'Replace the label set on an issue. Pass [] to clear all.',
|
|
322
|
+
handler: async (args, ctx) => {
|
|
323
|
+
const projectId = asString(args.projectId, 'projectId');
|
|
324
|
+
const issueId = asString(args.issueId, 'issueId');
|
|
325
|
+
if (!Array.isArray(args.labels))
|
|
326
|
+
throw new Error('labels must be string[]');
|
|
327
|
+
const labels = args.labels.map((l) => {
|
|
328
|
+
if (typeof l !== 'string')
|
|
329
|
+
throw new Error('each label must be a string');
|
|
330
|
+
return l;
|
|
331
|
+
});
|
|
332
|
+
return await adminPatch(ctx, `/projects/${projectId}/issues/${issueId}`, {
|
|
333
|
+
labels,
|
|
334
|
+
});
|
|
335
|
+
},
|
|
336
|
+
inputSchema: {
|
|
337
|
+
properties: {
|
|
338
|
+
issueId: { type: 'string' },
|
|
339
|
+
labels: { items: { type: 'string' }, type: 'array' },
|
|
340
|
+
projectId: { type: 'string' },
|
|
341
|
+
},
|
|
342
|
+
required: ['projectId', 'issueId', 'labels'],
|
|
343
|
+
type: 'object',
|
|
344
|
+
},
|
|
345
|
+
name: 'sentori_issue_set_labels',
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
description: 'Subscribe (watch=true) or unsubscribe (watch=false) the configured caller to an issue.',
|
|
349
|
+
handler: async (args, ctx) => {
|
|
350
|
+
const projectId = asString(args.projectId, 'projectId');
|
|
351
|
+
const issueId = asString(args.issueId, 'issueId');
|
|
352
|
+
const watch = args.watch === true;
|
|
353
|
+
if (watch) {
|
|
354
|
+
return await adminPut(ctx, `/projects/${projectId}/issues/${issueId}/watch`);
|
|
355
|
+
}
|
|
356
|
+
return await adminDelete(ctx, `/projects/${projectId}/issues/${issueId}/watch`);
|
|
357
|
+
},
|
|
358
|
+
inputSchema: {
|
|
359
|
+
properties: {
|
|
360
|
+
issueId: { type: 'string' },
|
|
361
|
+
projectId: { type: 'string' },
|
|
362
|
+
watch: { type: 'boolean' },
|
|
363
|
+
},
|
|
364
|
+
required: ['projectId', 'issueId', 'watch'],
|
|
365
|
+
type: 'object',
|
|
366
|
+
},
|
|
367
|
+
name: 'sentori_issue_watch',
|
|
368
|
+
},
|
|
369
|
+
];
|
|
370
|
+
}
|
|
371
|
+
//# sourceMappingURL=mcp.js.map
|
package/lib/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
|
package/lib/push.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type PushClientConfig = {
|
|
2
|
+
apiUrl: string;
|
|
3
|
+
projectId: string;
|
|
4
|
+
token: string;
|
|
5
|
+
};
|
|
6
|
+
type AdminCredentialRow = {
|
|
7
|
+
provider: string;
|
|
8
|
+
config: Record<string, unknown>;
|
|
9
|
+
updatedAt: string;
|
|
10
|
+
};
|
|
11
|
+
type Ticket = {
|
|
12
|
+
id: string;
|
|
13
|
+
status: 'queued' | 'sent' | 'failed';
|
|
14
|
+
providerOutcome?: string | null;
|
|
15
|
+
error?: string | null;
|
|
16
|
+
retryCount: number;
|
|
17
|
+
createdAt: string;
|
|
18
|
+
sentAt?: string | null;
|
|
19
|
+
};
|
|
20
|
+
/** Parse a CLI flag value that may be `@file.json` (read from disk
|
|
21
|
+
* and parse) or a literal JSON string. */
|
|
22
|
+
export declare function parseJsonArg(raw: string, kind: string): unknown;
|
|
23
|
+
export declare function pushCredsList(cfg: PushClientConfig): Promise<AdminCredentialRow[]>;
|
|
24
|
+
export declare function pushCredsSet(cfg: PushClientConfig, provider: string, config: unknown, secret: unknown): Promise<{
|
|
25
|
+
ok: boolean;
|
|
26
|
+
}>;
|
|
27
|
+
export declare function pushCredsDelete(cfg: PushClientConfig, provider: string): Promise<void>;
|
|
28
|
+
export type SendOpts = {
|
|
29
|
+
to: string;
|
|
30
|
+
title?: string;
|
|
31
|
+
body?: string;
|
|
32
|
+
data?: unknown;
|
|
33
|
+
priority?: 'high' | 'normal';
|
|
34
|
+
ttl?: number;
|
|
35
|
+
idempotencyKey?: string;
|
|
36
|
+
};
|
|
37
|
+
export declare function pushSend(cfg: PushClientConfig, opts: SendOpts): Promise<Ticket>;
|
|
38
|
+
export declare function pushReceipt(cfg: PushClientConfig, sendId: string): Promise<{
|
|
39
|
+
ticket: Ticket;
|
|
40
|
+
}>;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=push.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../src/push.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,KAAK,kBAAkB,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,KAAK,MAAM,GAAG;IACZ,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAA;IACpC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB,CAAA;AA+BD;2CAC2C;AAC3C,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAe/D;AAID,wBAAsB,aAAa,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAKxF;AAED,wBAAsB,YAAY,CAChC,GAAG,EAAE,gBAAgB,EACrB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,OAAO,GACd,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAA;CAAE,CAAC,CAc1B;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,gBAAgB,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CASf;AAID,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,wBAAsB,QAAQ,CAAC,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAuBrF;AAED,wBAAsB,WAAW,CAC/B,GAAG,EAAE,gBAAgB,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAK7B"}
|
package/lib/push.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// v2.12 — `sentori-cli push *` commands.
|
|
2
|
+
//
|
|
3
|
+
// Wraps the v2.7 admin REST + v2.7 ingest endpoints so operators can
|
|
4
|
+
// drive credential CRUD, ad-hoc sends, and receipt lookups from the
|
|
5
|
+
// terminal without touching curl.
|
|
6
|
+
//
|
|
7
|
+
// `push send` POST /v1/push/send (ingest Bearer)
|
|
8
|
+
// `push receipt` GET /v1/push/receipts/:id (ingest Bearer)
|
|
9
|
+
// `push creds list` GET /admin/api/projects/:id/push/credentials (admin Bearer)
|
|
10
|
+
// `push creds set` PUT /admin/api/projects/:id/push/credentials (admin Bearer)
|
|
11
|
+
// `push creds delete` DELETE /admin/api/projects/:id/push/credentials/:provider
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
const VALID_PROVIDERS = new Set(['apns', 'fcm', 'webpush', 'hcm', 'mipush']);
|
|
14
|
+
function joinUrl(base, path) {
|
|
15
|
+
return `${base.replace(/\/+$/, '')}${path}`;
|
|
16
|
+
}
|
|
17
|
+
async function bearerFetch(url, token, init) {
|
|
18
|
+
const resp = await fetch(url, {
|
|
19
|
+
...init,
|
|
20
|
+
headers: {
|
|
21
|
+
Authorization: `Bearer ${token}`,
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
...(init?.headers ?? {}),
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
if (!resp.ok) {
|
|
27
|
+
const detail = await resp.text().catch(() => '');
|
|
28
|
+
throw new Error(`${resp.status} ${resp.statusText}${detail ? ` — ${detail.slice(0, 300)}` : ''}`);
|
|
29
|
+
}
|
|
30
|
+
const txt = await resp.text();
|
|
31
|
+
return (txt ? JSON.parse(txt) : null);
|
|
32
|
+
}
|
|
33
|
+
/** Parse a CLI flag value that may be `@file.json` (read from disk
|
|
34
|
+
* and parse) or a literal JSON string. */
|
|
35
|
+
export function parseJsonArg(raw, kind) {
|
|
36
|
+
if (raw.startsWith('@')) {
|
|
37
|
+
const path = raw.slice(1);
|
|
38
|
+
const body = readFileSync(path, 'utf-8');
|
|
39
|
+
try {
|
|
40
|
+
return JSON.parse(body);
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
throw new Error(`${kind} file ${path} is not valid JSON: ${e.message}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
return JSON.parse(raw);
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
throw new Error(`${kind} arg is not valid JSON: ${e.message}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// ── credential CRUD ───────────────────────────────────────────────
|
|
54
|
+
export async function pushCredsList(cfg) {
|
|
55
|
+
return bearerFetch(joinUrl(cfg.apiUrl, `/admin/api/projects/${cfg.projectId}/push/credentials`), cfg.token);
|
|
56
|
+
}
|
|
57
|
+
export async function pushCredsSet(cfg, provider, config, secret) {
|
|
58
|
+
if (!VALID_PROVIDERS.has(provider)) {
|
|
59
|
+
throw new Error(`invalid provider '${provider}'; expected one of ${[...VALID_PROVIDERS].join('/')}`);
|
|
60
|
+
}
|
|
61
|
+
return bearerFetch(joinUrl(cfg.apiUrl, `/admin/api/projects/${cfg.projectId}/push/credentials`), cfg.token, {
|
|
62
|
+
body: JSON.stringify({ provider, config, secret }),
|
|
63
|
+
method: 'PUT',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
export async function pushCredsDelete(cfg, provider) {
|
|
67
|
+
await bearerFetch(joinUrl(cfg.apiUrl, `/admin/api/projects/${cfg.projectId}/push/credentials/${provider}`), cfg.token, { method: 'DELETE' });
|
|
68
|
+
}
|
|
69
|
+
export async function pushSend(cfg, opts) {
|
|
70
|
+
const payload = {
|
|
71
|
+
to: opts.to,
|
|
72
|
+
title: opts.title,
|
|
73
|
+
body: opts.body,
|
|
74
|
+
data: opts.data,
|
|
75
|
+
idempotencyKey: opts.idempotencyKey,
|
|
76
|
+
};
|
|
77
|
+
if (opts.priority || opts.ttl != null) {
|
|
78
|
+
payload.options = { priority: opts.priority, ttl: opts.ttl };
|
|
79
|
+
}
|
|
80
|
+
const resp = await bearerFetch(joinUrl(cfg.apiUrl, '/v1/push/send'), cfg.token, {
|
|
81
|
+
body: JSON.stringify(payload),
|
|
82
|
+
method: 'POST',
|
|
83
|
+
});
|
|
84
|
+
if (!resp.tickets?.length) {
|
|
85
|
+
throw new Error('server returned no tickets');
|
|
86
|
+
}
|
|
87
|
+
return resp.tickets[0];
|
|
88
|
+
}
|
|
89
|
+
export async function pushReceipt(cfg, sendId) {
|
|
90
|
+
return bearerFetch(joinUrl(cfg.apiUrl, `/v1/push/receipts/${encodeURIComponent(sendId)}`), cfg.token);
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=push.js.map
|
package/lib/push.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"push.js","sourceRoot":"","sources":["../src/push.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AdminUpload } from './native-artifacts.js';
|
|
2
|
+
export type SourceBundleUploadOptions = AdminUpload & {
|
|
3
|
+
/** v1.4 W26 — optional module label so polyrepo apps (main +
|
|
4
|
+
* watch ext + share ext etc.) can upload multiple bundles per
|
|
5
|
+
* (release, platform). Empty/undefined → unlabelled single
|
|
6
|
+
* bundle (v1.3 W15 behaviour). */
|
|
7
|
+
module?: string;
|
|
8
|
+
/** Pre-built tar.gz archive of the project's source tree. */
|
|
9
|
+
path: string;
|
|
10
|
+
platform: 'android' | 'ios';
|
|
11
|
+
};
|
|
12
|
+
export type SourceBundleUploadResult = {
|
|
13
|
+
contentHash: string;
|
|
14
|
+
kind: string;
|
|
15
|
+
sizeBytes: number;
|
|
16
|
+
};
|
|
17
|
+
export declare function uploadSourceBundle(opts: SourceBundleUploadOptions): Promise<SourceBundleUploadResult>;
|
|
18
|
+
/** Walk `dir`, pick platform-relevant source files, and tar.gz them
|
|
19
|
+
* into a temp file. Caller is responsible for invoking `cleanup()`.
|
|
20
|
+
* Uses the system `tar` binary; that's portable enough on macOS +
|
|
21
|
+
* Linux + WSL, which covers every realistic CI environment Sentori
|
|
22
|
+
* ships to. Native Windows CI without WSL would need to gzip the
|
|
23
|
+
* archive themselves (the pre-built-path mode still works). */
|
|
24
|
+
export declare function buildSourceBundleFromDir(dir: string, platform: 'android' | 'ios'): Promise<{
|
|
25
|
+
cleanup: () => Promise<void>;
|
|
26
|
+
path: string;
|
|
27
|
+
}>;
|
|
28
|
+
//# sourceMappingURL=source-bundle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-bundle.d.ts","sourceRoot":"","sources":["../src/source-bundle.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAyBxD,MAAM,MAAM,yBAAyB,GAAG,WAAW,GAAG;IACpD;;;uCAGmC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,SAAS,GAAG,KAAK,CAAA;CAC5B,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;CAClB,CAAA;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,wBAAwB,CAAC,CA6BnC;AAuDD;;;;;gEAKgE;AAChE,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,SAAS,GAAG,KAAK,GAC1B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAuCzD"}
|