crispctl 0.0.0 → 0.1.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/LICENSE +21 -0
- package/README.md +140 -1
- package/dist/args.d.ts +28 -0
- package/dist/args.js +156 -0
- package/dist/args.js.map +1 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +295 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +28 -0
- package/dist/client.js +181 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +45 -0
- package/dist/config.js +220 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.js +36 -0
- package/dist/errors.js.map +1 -0
- package/dist/help.d.ts +19 -0
- package/dist/help.js +175 -0
- package/dist/help.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/output.d.ts +11 -0
- package/dist/output.js +50 -0
- package/dist/output.js.map +1 -0
- package/dist/redact.d.ts +1 -0
- package/dist/redact.js +12 -0
- package/dist/redact.js.map +1 -0
- package/dist/rtm.d.ts +4 -0
- package/dist/rtm.js +25 -0
- package/dist/rtm.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/package.json +52 -3
package/dist/help.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
export const usage = {
|
|
2
|
+
authSet: "crispctl auth set [--profile <name>] --identifier <id> --key <key> --tier <website|plugin> --website <website_id>",
|
|
3
|
+
authShow: "crispctl auth show [--profile <name>]",
|
|
4
|
+
conversationsList: "crispctl conversations list [--page <n>]",
|
|
5
|
+
conversationsGet: "crispctl conversations get <session>",
|
|
6
|
+
conversationsSearch: "crispctl conversations search <query> [--page <n>] [--search-type text|segment]",
|
|
7
|
+
messagesList: "crispctl messages list <session>",
|
|
8
|
+
reply: "crispctl reply <session> (--text <message> | --note <note>)",
|
|
9
|
+
resolve: "crispctl resolve <session>",
|
|
10
|
+
reopen: "crispctl reopen <session>",
|
|
11
|
+
assign: "crispctl assign <session> (--user <id> | --unassign)",
|
|
12
|
+
segments: "crispctl segments <session> --set <a,b>",
|
|
13
|
+
read: "crispctl read <session>",
|
|
14
|
+
peopleGet: "crispctl people get <id|email>",
|
|
15
|
+
operatorsList: "crispctl operators list",
|
|
16
|
+
listen: "crispctl listen",
|
|
17
|
+
};
|
|
18
|
+
const globals = "Global flags: --json, --profile <name>, --website <id>";
|
|
19
|
+
export const ROOT_HELP = `crispctl — agent-friendly Crisp REST CLI
|
|
20
|
+
|
|
21
|
+
Usage:
|
|
22
|
+
crispctl [--json] [--profile <name>] [--website <id>] <command> [args]
|
|
23
|
+
|
|
24
|
+
${globals}
|
|
25
|
+
|
|
26
|
+
Commands:
|
|
27
|
+
auth set Save identifier, key, tier, and website_id
|
|
28
|
+
auth show Show the resolved profile (key redacted)
|
|
29
|
+
conversations list List conversations
|
|
30
|
+
conversations get Get one conversation
|
|
31
|
+
conversations search Search conversations
|
|
32
|
+
messages list List messages in a session
|
|
33
|
+
reply Send an operator message or private note
|
|
34
|
+
resolve Set conversation state to resolved
|
|
35
|
+
reopen Set conversation state to unresolved
|
|
36
|
+
assign Assign or unassign an operator
|
|
37
|
+
segments Replace conversation segments
|
|
38
|
+
read Mark the conversation read for the operator
|
|
39
|
+
people get Get a people profile by id or email
|
|
40
|
+
operators list List website operators
|
|
41
|
+
listen Stub. RTM is not implemented
|
|
42
|
+
|
|
43
|
+
Profiles:
|
|
44
|
+
Named profiles live in the config file. "default" and "sandbox" are the usual names.
|
|
45
|
+
--profile and CRISPCTL_PROFILE select one. The file remembers the last profile written by auth set.
|
|
46
|
+
|
|
47
|
+
Environment (overrides the selected profile):
|
|
48
|
+
CRISPCTL_PROFILE
|
|
49
|
+
CRISPCTL_IDENTIFIER or CRISP_IDENTIFIER
|
|
50
|
+
CRISPCTL_KEY or CRISP_KEY
|
|
51
|
+
CRISPCTL_WEBSITE_ID or CRISP_WEBSITE_ID
|
|
52
|
+
CRISPCTL_TIER or CRISP_TIER
|
|
53
|
+
CRISPCTL_CONFIG Config file path (default: $XDG_CONFIG_HOME/crispctl/config.json)
|
|
54
|
+
|
|
55
|
+
The token key is never printed. A config file written by crispctl is mode 0600.
|
|
56
|
+
|
|
57
|
+
Sandbox: use the Cos Crisp sandbox website only. Never point crispctl at production Teachify.
|
|
58
|
+
`;
|
|
59
|
+
const HELP = {
|
|
60
|
+
auth: `crispctl auth
|
|
61
|
+
|
|
62
|
+
auth set Save a profile
|
|
63
|
+
auth show Show the resolved profile with the key redacted
|
|
64
|
+
|
|
65
|
+
${usage.authSet}
|
|
66
|
+
${usage.authShow}
|
|
67
|
+
`,
|
|
68
|
+
"auth set": `${usage.authSet}
|
|
69
|
+
|
|
70
|
+
Writes the selected profile and makes it current. Flags win, then CRISPCTL_* / CRISP_* env, then the existing profile.
|
|
71
|
+
--website and --website-id both set website_id. Tier is website or plugin.
|
|
72
|
+
`,
|
|
73
|
+
"auth show": `${usage.authShow}
|
|
74
|
+
|
|
75
|
+
Prints profile, identifier, tier, website_id, whether the key is set, and where each value came from.
|
|
76
|
+
The key value is not included.
|
|
77
|
+
`,
|
|
78
|
+
conversations: `crispctl conversations
|
|
79
|
+
|
|
80
|
+
conversations list
|
|
81
|
+
conversations get <session>
|
|
82
|
+
conversations search <query>
|
|
83
|
+
`,
|
|
84
|
+
"conversations list": `${usage.conversationsList}
|
|
85
|
+
|
|
86
|
+
GET /v1/website/{website_id}/conversations/{page}
|
|
87
|
+
`,
|
|
88
|
+
"conversations get": `${usage.conversationsGet}
|
|
89
|
+
|
|
90
|
+
GET /v1/website/{website_id}/conversation/{session}
|
|
91
|
+
`,
|
|
92
|
+
"conversations search": `${usage.conversationsSearch}
|
|
93
|
+
|
|
94
|
+
GET /v1/website/{website_id}/conversations/{page}?search_query&search_type
|
|
95
|
+
search_type is text (default) or segment.
|
|
96
|
+
`,
|
|
97
|
+
messages: `crispctl messages list <session>
|
|
98
|
+
|
|
99
|
+
${usage.messagesList}
|
|
100
|
+
`,
|
|
101
|
+
"messages list": `${usage.messagesList}
|
|
102
|
+
|
|
103
|
+
GET /v1/website/{website_id}/conversation/{session}/messages
|
|
104
|
+
`,
|
|
105
|
+
reply: `${usage.reply}
|
|
106
|
+
|
|
107
|
+
POST /v1/website/{website_id}/conversation/{session}/message
|
|
108
|
+
--text sends {"type":"text","from":"operator","origin":"chat","content":"..."}
|
|
109
|
+
--note sends {"type":"note","from":"operator","origin":"chat","content":"..."}
|
|
110
|
+
`,
|
|
111
|
+
resolve: `${usage.resolve}
|
|
112
|
+
|
|
113
|
+
PATCH /v1/website/{website_id}/conversation/{session}/state
|
|
114
|
+
Body: {"state":"resolved"}
|
|
115
|
+
`,
|
|
116
|
+
reopen: `${usage.reopen}
|
|
117
|
+
|
|
118
|
+
PATCH /v1/website/{website_id}/conversation/{session}/state
|
|
119
|
+
Body: {"state":"unresolved"}
|
|
120
|
+
`,
|
|
121
|
+
assign: `${usage.assign}
|
|
122
|
+
|
|
123
|
+
PATCH /v1/website/{website_id}/conversation/{session}/routing
|
|
124
|
+
--user sends {"assigned":{"user_id":"<id>"}}
|
|
125
|
+
--unassign sends {"assigned":null}
|
|
126
|
+
`,
|
|
127
|
+
segments: `${usage.segments}
|
|
128
|
+
|
|
129
|
+
PATCH /v1/website/{website_id}/conversation/{session}/meta
|
|
130
|
+
Body: {"segments":["a","b"]}
|
|
131
|
+
`,
|
|
132
|
+
read: `${usage.read}
|
|
133
|
+
|
|
134
|
+
PATCH /v1/website/{website_id}/conversation/{session}/read
|
|
135
|
+
Body: {"from":"operator","origin":"chat"}
|
|
136
|
+
`,
|
|
137
|
+
people: `crispctl people get <id|email>
|
|
138
|
+
|
|
139
|
+
${usage.peopleGet}
|
|
140
|
+
`,
|
|
141
|
+
"people get": `${usage.peopleGet}
|
|
142
|
+
|
|
143
|
+
A people id calls GET /v1/website/{website_id}/people/profile/{people_id}.
|
|
144
|
+
An email is not placed on that path. crispctl searches
|
|
145
|
+
GET /v1/website/{website_id}/people/profiles/1?search_text=<email>
|
|
146
|
+
and then fetches the people_id whose email matches exactly.
|
|
147
|
+
`,
|
|
148
|
+
operators: `crispctl operators list
|
|
149
|
+
|
|
150
|
+
${usage.operatorsList}
|
|
151
|
+
`,
|
|
152
|
+
"operators list": `${usage.operatorsList}
|
|
153
|
+
|
|
154
|
+
GET /v1/website/{website_id}/operators/list
|
|
155
|
+
`,
|
|
156
|
+
listen: `${usage.listen}
|
|
157
|
+
|
|
158
|
+
RTM listen is not implemented. See the command output for the website-tier connect-endpoints pitfall.
|
|
159
|
+
`,
|
|
160
|
+
};
|
|
161
|
+
export function renderHelp(positionals) {
|
|
162
|
+
const key = positionals.join(" ");
|
|
163
|
+
if (!key) {
|
|
164
|
+
return ROOT_HELP;
|
|
165
|
+
}
|
|
166
|
+
if (HELP[key]) {
|
|
167
|
+
return HELP[key];
|
|
168
|
+
}
|
|
169
|
+
const head = positionals[0];
|
|
170
|
+
if (head && HELP[head]) {
|
|
171
|
+
return HELP[head];
|
|
172
|
+
}
|
|
173
|
+
return `${ROOT_HELP}\nUnknown command: ${positionals[0] ?? ""}\n`;
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=help.js.map
|
package/dist/help.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,OAAO,EAAE,mHAAmH;IAC5H,QAAQ,EAAE,uCAAuC;IACjD,iBAAiB,EAAE,0CAA0C;IAC7D,gBAAgB,EAAE,sCAAsC;IACxD,mBAAmB,EAAE,iFAAiF;IACtG,YAAY,EAAE,kCAAkC;IAChD,KAAK,EAAE,6DAA6D;IACpE,OAAO,EAAE,4BAA4B;IACrC,MAAM,EAAE,2BAA2B;IACnC,MAAM,EAAE,sDAAsD;IAC9D,QAAQ,EAAE,yCAAyC;IACnD,IAAI,EAAE,yBAAyB;IAC/B,SAAS,EAAE,gCAAgC;IAC3C,aAAa,EAAE,yBAAyB;IACxC,MAAM,EAAE,iBAAiB;CACjB,CAAA;AAEV,MAAM,OAAO,GAAG,wDAAwD,CAAA;AAExE,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;EAKvB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCR,CAAA;AAED,MAAM,IAAI,GAA2B;IACnC,IAAI,EAAE;;;;;EAKN,KAAK,CAAC,OAAO;EACb,KAAK,CAAC,QAAQ;CACf;IACC,UAAU,EAAE,GAAG,KAAK,CAAC,OAAO;;;;CAI7B;IACC,WAAW,EAAE,GAAG,KAAK,CAAC,QAAQ;;;;CAI/B;IACC,aAAa,EAAE;;;;;CAKhB;IACC,oBAAoB,EAAE,GAAG,KAAK,CAAC,iBAAiB;;;CAGjD;IACC,mBAAmB,EAAE,GAAG,KAAK,CAAC,gBAAgB;;;CAG/C;IACC,sBAAsB,EAAE,GAAG,KAAK,CAAC,mBAAmB;;;;CAIrD;IACC,QAAQ,EAAE;;EAEV,KAAK,CAAC,YAAY;CACnB;IACC,eAAe,EAAE,GAAG,KAAK,CAAC,YAAY;;;CAGvC;IACC,KAAK,EAAE,GAAG,KAAK,CAAC,KAAK;;;;;CAKtB;IACC,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO;;;;CAI1B;IACC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM;;;;CAIxB;IACC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM;;;;;CAKxB;IACC,QAAQ,EAAE,GAAG,KAAK,CAAC,QAAQ;;;;CAI5B;IACC,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI;;;;CAIpB;IACC,MAAM,EAAE;;EAER,KAAK,CAAC,SAAS;CAChB;IACC,YAAY,EAAE,GAAG,KAAK,CAAC,SAAS;;;;;;CAMjC;IACC,SAAS,EAAE;;EAEX,KAAK,CAAC,aAAa;CACpB;IACC,gBAAgB,EAAE,GAAG,KAAK,CAAC,aAAa;;;CAGzC;IACC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM;;;CAGxB;CACA,CAAA;AAED,MAAM,UAAU,UAAU,CAAC,WAA8B;IACvD,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACjC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACd,OAAO,IAAI,CAAC,GAAG,CAAC,CAAA;IAClB,CAAC;IACD,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;IAC3B,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC,IAAI,CAAC,CAAA;IACnB,CAAC;IACD,OAAO,GAAG,SAAS,sBAAsB,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAA;AACnE,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { realpathSync } from "node:fs";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { run } from "./cli.js";
|
|
5
|
+
export function isDirectInvocation(entry = process.argv[1], moduleUrl = import.meta.url) {
|
|
6
|
+
if (!entry)
|
|
7
|
+
return false;
|
|
8
|
+
try {
|
|
9
|
+
return moduleUrl === pathToFileURL(realpathSync(entry)).href;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (isDirectInvocation()) {
|
|
16
|
+
process.exitCode = await run(process.argv.slice(2));
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAE9B,MAAM,UAAU,kBAAkB,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG;IACrF,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAA;IACxB,IAAI,CAAC;QACH,OAAO,SAAS,KAAK,aAAa,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED,IAAI,kBAAkB,EAAE,EAAE,CAAC;IACzB,OAAO,CAAC,QAAQ,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;AACrD,CAAC"}
|
package/dist/output.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type ErrorPayload = {
|
|
2
|
+
ok: false;
|
|
3
|
+
error: string;
|
|
4
|
+
message: string;
|
|
5
|
+
status?: number;
|
|
6
|
+
reason?: string;
|
|
7
|
+
retry_after?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function writeOut(stdout: (chunk: string) => void, json: boolean, value: unknown): void;
|
|
10
|
+
export declare function errorPayload(err: unknown, secrets: readonly (string | undefined)[]): ErrorPayload;
|
|
11
|
+
export declare function writeErr(stderr: (chunk: string) => void, json: boolean, err: unknown, secrets: readonly (string | undefined)[]): void;
|
package/dist/output.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { CrispApiError, ConfigError, UsageError } from "./errors.js";
|
|
2
|
+
import { redactSecrets } from "./redact.js";
|
|
3
|
+
export function writeOut(stdout, json, value) {
|
|
4
|
+
if (!json && typeof value === "string") {
|
|
5
|
+
stdout(value.endsWith("\n") ? value : `${value}\n`);
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
stdout(`${json ? JSON.stringify(value) : JSON.stringify(value, null, 2)}\n`);
|
|
9
|
+
}
|
|
10
|
+
export function errorPayload(err, secrets) {
|
|
11
|
+
if (err instanceof CrispApiError) {
|
|
12
|
+
const payload = {
|
|
13
|
+
ok: false,
|
|
14
|
+
error: err.reason,
|
|
15
|
+
status: err.status,
|
|
16
|
+
reason: err.reason,
|
|
17
|
+
message: redactSecrets(err.message, secrets),
|
|
18
|
+
};
|
|
19
|
+
if (err.retryAfter) {
|
|
20
|
+
payload.retry_after = err.retryAfter;
|
|
21
|
+
}
|
|
22
|
+
return payload;
|
|
23
|
+
}
|
|
24
|
+
if (err instanceof UsageError) {
|
|
25
|
+
return { ok: false, error: "usage", message: redactSecrets(err.message, secrets) };
|
|
26
|
+
}
|
|
27
|
+
if (err instanceof ConfigError) {
|
|
28
|
+
return { ok: false, error: "config", message: redactSecrets(err.message, secrets) };
|
|
29
|
+
}
|
|
30
|
+
const message = err instanceof Error ? err.message : "unknown error";
|
|
31
|
+
return { ok: false, error: "error", message: redactSecrets(message, secrets) };
|
|
32
|
+
}
|
|
33
|
+
export function writeErr(stderr, json, err, secrets) {
|
|
34
|
+
const payload = errorPayload(err, secrets);
|
|
35
|
+
if (json) {
|
|
36
|
+
stderr(`${JSON.stringify(payload)}\n`);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if ((payload.error === "usage" || payload.error === "config") && payload.status === undefined) {
|
|
40
|
+
stderr(`error: ${payload.message}\n`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const head = [payload.status, payload.reason || payload.error].filter((part) => part !== undefined && part !== "").join(" ");
|
|
44
|
+
if (payload.message && payload.message !== payload.reason && payload.message !== payload.error) {
|
|
45
|
+
stderr(`error: ${head}: ${payload.message}\n`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
stderr(`error: ${head}\n`);
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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"}
|
package/dist/redact.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function redactSecrets(message: string, secrets: readonly (string | undefined)[]): string;
|
package/dist/redact.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function redactSecrets(message, secrets) {
|
|
2
|
+
const present = [...new Set(secrets.filter((secret) => typeof secret === "string" && secret.length > 0))];
|
|
3
|
+
if (present.length === 0)
|
|
4
|
+
return message;
|
|
5
|
+
present.sort((left, right) => right.length - left.length);
|
|
6
|
+
const pattern = new RegExp(present.map(escapeRegExp).join("|"), "g");
|
|
7
|
+
return message.replace(pattern, "[redacted]");
|
|
8
|
+
}
|
|
9
|
+
function escapeRegExp(value) {
|
|
10
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,aAAa,CAAC,OAAe,EAAE,OAAwC;IACrF,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAoB,EAAE,CAAC,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;IAC3H,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAA;IACxC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;IACzD,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAA;IACpE,OAAO,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,YAAY,CAAC,CAAA;AAC/C,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAA;AACrD,CAAC"}
|
package/dist/rtm.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const SDK_WEBSITE_TIER_CONNECT_PATH = "/v1/website/connect/endpoints";
|
|
2
|
+
export declare const PLUGIN_CONNECT_PATH = "/v1/plugin/connect/endpoints";
|
|
3
|
+
export declare function connectEndpointsPath(tier: "website" | "plugin", websiteId: string): string;
|
|
4
|
+
export declare function listenStubMessage(websiteId?: string): string;
|
package/dist/rtm.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const SDK_WEBSITE_TIER_CONNECT_PATH = "/v1/website/connect/endpoints";
|
|
2
|
+
export const PLUGIN_CONNECT_PATH = "/v1/plugin/connect/endpoints";
|
|
3
|
+
export function connectEndpointsPath(tier, websiteId) {
|
|
4
|
+
if (tier === "plugin") {
|
|
5
|
+
return PLUGIN_CONNECT_PATH;
|
|
6
|
+
}
|
|
7
|
+
return `/v1/website/${encodeURIComponent(websiteId)}/connect/endpoints`;
|
|
8
|
+
}
|
|
9
|
+
export function listenStubMessage(websiteId) {
|
|
10
|
+
const correct = websiteId
|
|
11
|
+
? connectEndpointsPath("website", websiteId)
|
|
12
|
+
: "/v1/website/{website_id}/connect/endpoints";
|
|
13
|
+
return [
|
|
14
|
+
"listen is not implemented (RTM is a follow-up).",
|
|
15
|
+
"",
|
|
16
|
+
"Website-tier pitfall: the official crisp-api Node SDK requests",
|
|
17
|
+
`GET ${SDK_WEBSITE_TIER_CONNECT_PATH}`,
|
|
18
|
+
"when the token tier is \"website\". That call omits website_id and does not work.",
|
|
19
|
+
`The correct website route is GET ${correct}.`,
|
|
20
|
+
`Plugin tier uses GET ${PLUGIN_CONNECT_PATH}, which the SDK does call.`,
|
|
21
|
+
"",
|
|
22
|
+
"Use the Cos Sandbox website only. Never point listen at production Teachify.",
|
|
23
|
+
].join("\n");
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=rtm.js.map
|
package/dist/rtm.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rtm.js","sourceRoot":"","sources":["../src/rtm.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,6BAA6B,GAAG,+BAA+B,CAAA;AAE5E,MAAM,CAAC,MAAM,mBAAmB,GAAG,8BAA8B,CAAA;AAEjE,MAAM,UAAU,oBAAoB,CAAC,IAA0B,EAAE,SAAiB;IAChF,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO,mBAAmB,CAAA;IAC5B,CAAC;IACD,OAAO,eAAe,kBAAkB,CAAC,SAAS,CAAC,oBAAoB,CAAA;AACzE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,SAAkB;IAClD,MAAM,OAAO,GAAG,SAAS;QACvB,CAAC,CAAC,oBAAoB,CAAC,SAAS,EAAE,SAAS,CAAC;QAC5C,CAAC,CAAC,4CAA4C,CAAA;IAChD,OAAO;QACL,iDAAiD;QACjD,EAAE;QACF,gEAAgE;QAChE,OAAO,6BAA6B,EAAE;QACtC,mFAAmF;QACnF,oCAAoC,OAAO,GAAG;QAC9C,wBAAwB,mBAAmB,4BAA4B;QACvE,EAAE;QACF,8EAA8E;KAC/E,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const version: string;
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
const pkg = JSON.parse(readFileSync(join(here, "..", "package.json"), "utf8"));
|
|
6
|
+
export const version = pkg.version;
|
|
7
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AACpD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAwB,CAAA;AAErG,MAAM,CAAC,MAAM,OAAO,GAAW,GAAG,CAAC,OAAO,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,57 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "crispctl",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Agent-friendly CLI for Crisp support operations",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "linyiru",
|
|
7
|
-
"
|
|
7
|
+
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"crispctl": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=20"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/solcreek/crisp-cli.git"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/solcreek/crisp-cli#readme",
|
|
24
|
+
"bugs": "https://github.com/solcreek/crisp-cli/issues",
|
|
25
|
+
"keywords": [
|
|
26
|
+
"crisp",
|
|
27
|
+
"cli",
|
|
28
|
+
"support"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc -p tsconfig.json",
|
|
32
|
+
"typecheck": "tsc -p tsconfig.test.json --noEmit",
|
|
33
|
+
"test": "c8 node --enable-source-maps --import tsx --test test/*.test.ts",
|
|
34
|
+
"test:live": "node --import tsx --test test/live/smoke.test.ts",
|
|
35
|
+
"prepublishOnly": "npm run build"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"undici": "^6.21.2"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^22.15.3",
|
|
42
|
+
"c8": "^10.1.3",
|
|
43
|
+
"tsx": "^4.20.3",
|
|
44
|
+
"typescript": "^5.8.3"
|
|
45
|
+
},
|
|
46
|
+
"c8": {
|
|
47
|
+
"all": true,
|
|
48
|
+
"src": ["src"],
|
|
49
|
+
"include": ["src/**/*.ts"],
|
|
50
|
+
"reporter": ["text", "text-summary"],
|
|
51
|
+
"check-coverage": true,
|
|
52
|
+
"lines": 80,
|
|
53
|
+
"statements": 80,
|
|
54
|
+
"functions": 80,
|
|
55
|
+
"branches": 75
|
|
56
|
+
}
|
|
8
57
|
}
|