@madewithremy/admin 0.1.3 → 0.1.4
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/dist/index.d.ts +105 -1
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -1
- package/dist/prod.js +207 -0
- package/package.json +1 -1
package/dist/prod.js
CHANGED
|
@@ -1887,6 +1887,82 @@ async function streamToStdout(ctx, apiPath, body) {
|
|
|
1887
1887
|
}
|
|
1888
1888
|
}
|
|
1889
1889
|
}
|
|
1890
|
+
async function tailSseToStdout(ctx, apiPath) {
|
|
1891
|
+
const controller = new AbortController();
|
|
1892
|
+
let idleTimer;
|
|
1893
|
+
let idled = false;
|
|
1894
|
+
const armIdleTimer = () => {
|
|
1895
|
+
if (idleTimer) {
|
|
1896
|
+
clearTimeout(idleTimer);
|
|
1897
|
+
}
|
|
1898
|
+
idleTimer = setTimeout(() => {
|
|
1899
|
+
idled = true;
|
|
1900
|
+
controller.abort();
|
|
1901
|
+
}, STREAM_IDLE_TIMEOUT_MS);
|
|
1902
|
+
};
|
|
1903
|
+
let complete = false;
|
|
1904
|
+
try {
|
|
1905
|
+
armIdleTimer();
|
|
1906
|
+
const res = await fetch(`${ctx.baseUrl}${apiPath}`, {
|
|
1907
|
+
method: "GET",
|
|
1908
|
+
headers: { ...authHeaders(ctx), Accept: "text/event-stream" },
|
|
1909
|
+
signal: controller.signal
|
|
1910
|
+
});
|
|
1911
|
+
if (!res.ok) {
|
|
1912
|
+
fatal(
|
|
1913
|
+
`API GET ${apiPath} returned ${res.status}: ${JSON.stringify(await readBody(res))}`
|
|
1914
|
+
);
|
|
1915
|
+
}
|
|
1916
|
+
if (!res.body) {
|
|
1917
|
+
fatal("Tail response has no body");
|
|
1918
|
+
}
|
|
1919
|
+
const reader = res.body.getReader();
|
|
1920
|
+
const decoder = new TextDecoder();
|
|
1921
|
+
let buffer = "";
|
|
1922
|
+
const emit = (line) => {
|
|
1923
|
+
if (!line.startsWith("data: ")) {
|
|
1924
|
+
return;
|
|
1925
|
+
}
|
|
1926
|
+
try {
|
|
1927
|
+
const value = JSON.parse(line.slice(6));
|
|
1928
|
+
if (value?.type === "tail_complete") {
|
|
1929
|
+
complete = true;
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
out(value);
|
|
1933
|
+
} catch {
|
|
1934
|
+
}
|
|
1935
|
+
};
|
|
1936
|
+
while (true) {
|
|
1937
|
+
const { done, value } = await reader.read();
|
|
1938
|
+
if (done) {
|
|
1939
|
+
emit(buffer);
|
|
1940
|
+
break;
|
|
1941
|
+
}
|
|
1942
|
+
armIdleTimer();
|
|
1943
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1944
|
+
const lines = buffer.split("\n");
|
|
1945
|
+
buffer = lines.pop();
|
|
1946
|
+
for (const line of lines) {
|
|
1947
|
+
emit(line);
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
} catch (err) {
|
|
1951
|
+
if (complete) {
|
|
1952
|
+
return;
|
|
1953
|
+
}
|
|
1954
|
+
if (idled || err?.name === "AbortError") {
|
|
1955
|
+
fatal(
|
|
1956
|
+
`Tail GET ${apiPath} stalled \u2014 no data for ${STREAM_IDLE_TIMEOUT_MS / 1e3}s`
|
|
1957
|
+
);
|
|
1958
|
+
}
|
|
1959
|
+
throw err;
|
|
1960
|
+
} finally {
|
|
1961
|
+
if (idleTimer) {
|
|
1962
|
+
clearTimeout(idleTimer);
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1890
1966
|
|
|
1891
1967
|
// src/ops/methods.ts
|
|
1892
1968
|
async function list6(ctx) {
|
|
@@ -3865,6 +3941,132 @@ Notes:
|
|
|
3865
3941
|
'remy-admin requests get <requestId>' for that call's input, output, stdout
|
|
3866
3942
|
and error. Client tools run in the browser, so they have no requestId.`;
|
|
3867
3943
|
|
|
3944
|
+
// src/ops/events.ts
|
|
3945
|
+
function channelsList(ctx, params = {}) {
|
|
3946
|
+
return call(
|
|
3947
|
+
ctx,
|
|
3948
|
+
"GET",
|
|
3949
|
+
`/_internal/v2/apps/${ctx.appId}/events/channels${qs(params)}`
|
|
3950
|
+
);
|
|
3951
|
+
}
|
|
3952
|
+
function publish(ctx, params) {
|
|
3953
|
+
return call(
|
|
3954
|
+
ctx,
|
|
3955
|
+
"POST",
|
|
3956
|
+
`/_internal/v2/apps/${ctx.appId}/events/publish`,
|
|
3957
|
+
{ channels: params.channels, data: params.data, scope: params.scope }
|
|
3958
|
+
);
|
|
3959
|
+
}
|
|
3960
|
+
|
|
3961
|
+
// src/commands/events.ts
|
|
3962
|
+
var eventsSpecs = {
|
|
3963
|
+
"events tail": {
|
|
3964
|
+
usage: "Usage: remy-admin events tail [<channel>] [--scope live] [--for 60]",
|
|
3965
|
+
positionals: [{ name: "channel" }],
|
|
3966
|
+
flags: {
|
|
3967
|
+
scope: { type: "string" },
|
|
3968
|
+
for: { type: "number", min: 1, max: 600 }
|
|
3969
|
+
}
|
|
3970
|
+
},
|
|
3971
|
+
"events publish": {
|
|
3972
|
+
usage: "Usage: remy-admin events publish <channel> <json> [--scope live]\nPublishes exactly as the app's own events.publish would \u2014 same validation, delivery, and metering.",
|
|
3973
|
+
positionals: [
|
|
3974
|
+
{ name: "channel", required: true },
|
|
3975
|
+
{ name: "json", required: true }
|
|
3976
|
+
],
|
|
3977
|
+
flags: {
|
|
3978
|
+
scope: { type: "string" }
|
|
3979
|
+
}
|
|
3980
|
+
},
|
|
3981
|
+
"events channels list": {
|
|
3982
|
+
usage: "Usage: remy-admin events channels list [--scope live]",
|
|
3983
|
+
flags: {
|
|
3984
|
+
scope: { type: "string" }
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3987
|
+
};
|
|
3988
|
+
async function eventsTail(ctx, a) {
|
|
3989
|
+
const params = new URLSearchParams();
|
|
3990
|
+
const channel = a.str("channel");
|
|
3991
|
+
if (channel) {
|
|
3992
|
+
params.set("channel", channel);
|
|
3993
|
+
}
|
|
3994
|
+
const scope = a.str("scope");
|
|
3995
|
+
if (scope) {
|
|
3996
|
+
params.set("scope", scope);
|
|
3997
|
+
}
|
|
3998
|
+
const forSeconds = a.num("for");
|
|
3999
|
+
if (forSeconds !== void 0) {
|
|
4000
|
+
params.set("forSeconds", String(forSeconds));
|
|
4001
|
+
}
|
|
4002
|
+
const query3 = params.toString();
|
|
4003
|
+
await tailSseToStdout(
|
|
4004
|
+
ctx,
|
|
4005
|
+
`/_internal/v2/apps/${ctx.appId}/events/tail${query3 ? `?${query3}` : ""}`
|
|
4006
|
+
);
|
|
4007
|
+
}
|
|
4008
|
+
async function eventsPublish(ctx, a) {
|
|
4009
|
+
const raw = a.req("json");
|
|
4010
|
+
let data;
|
|
4011
|
+
try {
|
|
4012
|
+
data = JSON.parse(raw);
|
|
4013
|
+
} catch {
|
|
4014
|
+
fatal(`Invalid JSON payload: ${raw}`);
|
|
4015
|
+
}
|
|
4016
|
+
out(
|
|
4017
|
+
await publish(ctx, {
|
|
4018
|
+
channels: a.req("channel"),
|
|
4019
|
+
data,
|
|
4020
|
+
scope: a.str("scope")
|
|
4021
|
+
})
|
|
4022
|
+
);
|
|
4023
|
+
}
|
|
4024
|
+
async function eventsChannelsList(ctx, a) {
|
|
4025
|
+
out(await channelsList(ctx, { scope: a.str("scope") }));
|
|
4026
|
+
}
|
|
4027
|
+
var eventsHandlers = {
|
|
4028
|
+
"events tail": eventsTail,
|
|
4029
|
+
"events publish": eventsPublish,
|
|
4030
|
+
"events channels list": eventsChannelsList
|
|
4031
|
+
};
|
|
4032
|
+
var eventsHelp = `remy-admin events \u2014 Observe and test the app's realtime events (publish/subscribe).
|
|
4033
|
+
|
|
4034
|
+
Subcommands:
|
|
4035
|
+
tail Print publishes live as they happen (bounded; default 60s, max 600)
|
|
4036
|
+
publish Publish a test event, exactly as the app's own events.publish would
|
|
4037
|
+
channels list Channels with recent publishes/subscriptions + live subscriber counts
|
|
4038
|
+
|
|
4039
|
+
Usage:
|
|
4040
|
+
remy-admin events tail [<channel>] [--scope live] [--for 60]
|
|
4041
|
+
remy-admin events publish <channel> <json> [--scope live]
|
|
4042
|
+
remy-admin events channels list [--scope live]
|
|
4043
|
+
|
|
4044
|
+
Examples:
|
|
4045
|
+
remy-admin events tail --for 30
|
|
4046
|
+
remy-admin events tail jobs:usr_123
|
|
4047
|
+
remy-admin events publish jobs:usr_123 '{"type":"ping"}'
|
|
4048
|
+
remy-admin events channels list
|
|
4049
|
+
|
|
4050
|
+
Notes:
|
|
4051
|
+
tail answers "is my backend publishing what I think it is": run it in one
|
|
4052
|
+
shell, trigger the publishing method in another, and each matching publish
|
|
4053
|
+
prints as one JSON value ({channel, data, ts}). It ends on its own after
|
|
4054
|
+
--for seconds (exit 0), so it is safe to run from a script.
|
|
4055
|
+
|
|
4056
|
+
publish lets a frontend subscriber be verified before the backend trigger
|
|
4057
|
+
exists. The response's 'delivered' counts live subscriber connections per
|
|
4058
|
+
published channel \u2014 0 means nobody is listening right now, which is normal,
|
|
4059
|
+
not an error.
|
|
4060
|
+
|
|
4061
|
+
channels list is the mismatch-finder: a channel with subscribers but no
|
|
4062
|
+
recent publish (or the reverse) usually means the frontend and backend spell
|
|
4063
|
+
the channel differently. Window is 24h; channels are exact strings \u2014 there
|
|
4064
|
+
are no wildcards anywhere in app events.
|
|
4065
|
+
|
|
4066
|
+
Scopes: events never cross execution environments. --scope defaults to
|
|
4067
|
+
'live'; use 'dev:<devSessionId>' to inspect a tunnel session's world or
|
|
4068
|
+
'preview:<releaseId>' for a branch preview.`;
|
|
4069
|
+
|
|
3868
4070
|
// src/ops/jewels.ts
|
|
3869
4071
|
var JEWEL_RUN_TIMEOUT_MS = 6e5;
|
|
3870
4072
|
function overview(ctx, params = {}) {
|
|
@@ -5148,6 +5350,7 @@ var SPECS = {
|
|
|
5148
5350
|
...dataSourcesSpecs,
|
|
5149
5351
|
...voiceSpecs,
|
|
5150
5352
|
...agentSpecs,
|
|
5353
|
+
...eventsSpecs,
|
|
5151
5354
|
...jewelsSpecs,
|
|
5152
5355
|
...settingsSpecs,
|
|
5153
5356
|
...emailSpecs,
|
|
@@ -5171,6 +5374,7 @@ var HANDLERS = {
|
|
|
5171
5374
|
...dataSourcesHandlers,
|
|
5172
5375
|
...voiceHandlers,
|
|
5173
5376
|
...agentHandlers,
|
|
5377
|
+
...eventsHandlers,
|
|
5174
5378
|
...jewelsHandlers,
|
|
5175
5379
|
...settingsHandlers,
|
|
5176
5380
|
...emailHandlers,
|
|
@@ -5194,6 +5398,7 @@ var GROUP_HELP = {
|
|
|
5194
5398
|
datasources: dataSourcesHelp,
|
|
5195
5399
|
voice: voiceHelp,
|
|
5196
5400
|
agent: agentHelp,
|
|
5401
|
+
events: eventsHelp,
|
|
5197
5402
|
jewels: jewelsHelp,
|
|
5198
5403
|
settings: settingsHelp,
|
|
5199
5404
|
email: emailHelp,
|
|
@@ -5274,6 +5479,7 @@ Commands:
|
|
|
5274
5479
|
datasources Build and query searchable document corpora (RAG)
|
|
5275
5480
|
voice Phone numbers, voice call log + transcripts, voice policy settings
|
|
5276
5481
|
agent Agent (chat) conversation log + transcripts
|
|
5482
|
+
events Realtime events \u2014 live tail, test publish, channel activity
|
|
5277
5483
|
jewels Monitor jewel shadowing; review + approve the proposal queue
|
|
5278
5484
|
settings App settings \u2014 signup allowlist, test accounts, embed origins, toggles
|
|
5279
5485
|
email Email \u2014 delivery log, blast stats, unsubscribes, inbox, custom domains
|
|
@@ -5305,6 +5511,7 @@ var GROUPS = [
|
|
|
5305
5511
|
"datasources",
|
|
5306
5512
|
"voice",
|
|
5307
5513
|
"agent",
|
|
5514
|
+
"events",
|
|
5308
5515
|
"jewels",
|
|
5309
5516
|
"settings",
|
|
5310
5517
|
"email",
|