latchkey 3.2.2 → 3.4.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 +2 -1
- package/dist/skills/generic/latchkey/SKILL.md +1 -1
- package/dist/skills/openclaw/latchkey/SKILL.md +1 -1
- package/dist/src/apiCredentials/serialization.d.ts +21 -0
- package/dist/src/apiCredentials/serialization.d.ts.map +1 -1
- package/dist/src/apiCredentials/serialization.js +7 -0
- package/dist/src/apiCredentials/serialization.js.map +1 -1
- package/dist/src/cliCommands.d.ts.map +1 -1
- package/dist/src/cliCommands.js +91 -7
- package/dist/src/cliCommands.js.map +1 -1
- package/dist/src/configDataStore.d.ts +18 -0
- package/dist/src/configDataStore.d.ts.map +1 -1
- package/dist/src/configDataStore.js +10 -0
- package/dist/src/configDataStore.js.map +1 -1
- package/dist/src/serviceRegistry.d.ts.map +1 -1
- package/dist/src/serviceRegistry.js +27 -3
- package/dist/src/serviceRegistry.js.map +1 -1
- package/dist/src/services/aws.d.ts.map +1 -1
- package/dist/src/services/aws.js +1 -2
- package/dist/src/services/aws.js.map +1 -1
- package/dist/src/services/core/base.d.ts +25 -3
- package/dist/src/services/core/base.d.ts.map +1 -1
- package/dist/src/services/core/base.js +32 -10
- package/dist/src/services/core/base.js.map +1 -1
- package/dist/src/services/core/loginFlows/base.d.ts +75 -0
- package/dist/src/services/core/loginFlows/base.d.ts.map +1 -0
- package/dist/src/services/core/loginFlows/base.js +47 -0
- package/dist/src/services/core/loginFlows/base.js.map +1 -0
- package/dist/src/services/core/loginFlows/cookieCapture.d.ts +55 -0
- package/dist/src/services/core/loginFlows/cookieCapture.d.ts.map +1 -0
- package/dist/src/services/core/loginFlows/cookieCapture.js +244 -0
- package/dist/src/services/core/loginFlows/cookieCapture.js.map +1 -0
- package/dist/src/services/core/loginFlows/registry.d.ts +30 -0
- package/dist/src/services/core/loginFlows/registry.d.ts.map +1 -0
- package/dist/src/services/core/loginFlows/registry.js +56 -0
- package/dist/src/services/core/loginFlows/registry.js.map +1 -0
- package/dist/src/services/core/registered.d.ts +38 -2
- package/dist/src/services/core/registered.d.ts.map +1 -1
- package/dist/src/services/core/registered.js +37 -2
- package/dist/src/services/core/registered.js.map +1 -1
- package/dist/src/services/index.d.ts +4 -0
- package/dist/src/services/index.d.ts.map +1 -1
- package/dist/src/services/index.js +4 -0
- package/dist/src/services/index.js.map +1 -1
- package/dist/src/services/ngrok.d.ts +38 -0
- package/dist/src/services/ngrok.d.ts.map +1 -0
- package/dist/src/services/ngrok.js +129 -0
- package/dist/src/services/ngrok.js.map +1 -0
- package/dist/src/services/zoom.d.ts +118 -5
- package/dist/src/services/zoom.d.ts.map +1 -1
- package/dist/src/services/zoom.js +692 -7
- package/dist/src/services/zoom.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/dist/tests/apiCredentials.test.js +5 -0
- package/dist/tests/apiCredentials.test.js.map +1 -1
- package/dist/tests/cli.test.js +178 -2
- package/dist/tests/cli.test.js.map +1 -1
- package/dist/tests/cookieCapture.test.d.ts +10 -0
- package/dist/tests/cookieCapture.test.d.ts.map +1 -0
- package/dist/tests/cookieCapture.test.js +221 -0
- package/dist/tests/cookieCapture.test.js.map +1 -0
- package/dist/tests/serviceRegistry.test.js +29 -8
- package/dist/tests/serviceRegistry.test.js.map +1 -1
- package/dist/tests/servicesAgainstRecordings.test.js +13 -11
- package/dist/tests/servicesAgainstRecordings.test.js.map +1 -1
- package/dist/tests/zoom.test.d.ts +2 -0
- package/dist/tests/zoom.test.d.ts.map +1 -0
- package/dist/tests/zoom.test.js +110 -0
- package/dist/tests/zoom.test.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A generic browser login that works for any cookie-authenticated service:
|
|
3
|
+
* open a URL, watch the `Set-Cookie` headers of the responses that follow, and
|
|
4
|
+
* capture named cookies as the credentials.
|
|
5
|
+
*
|
|
6
|
+
* The cookie mechanics — reading `Set-Cookie`, deciding where a cookie applies,
|
|
7
|
+
* writing a `Cookie` header — are RFC 6265 and not specific to this flow, but
|
|
8
|
+
* they stay private to it: nothing else needs them, and behind the LoginFlow
|
|
9
|
+
* interface nobody has to care how this flow works. If cookie handling is ever
|
|
10
|
+
* wanted elsewhere, this is the part to lift back out into a module of its own.
|
|
11
|
+
*
|
|
12
|
+
* The flow interprets the registered parameters; the session it creates holds
|
|
13
|
+
* the cookies of one login.
|
|
14
|
+
*
|
|
15
|
+
* Nothing here is service-specific — the cookie names come from whoever
|
|
16
|
+
* registered the service, as the parameters of the `cookie-capture` login flow.
|
|
17
|
+
*/
|
|
18
|
+
import { z } from 'zod';
|
|
19
|
+
import { RawCurlCredentials } from '../../../apiCredentials/base.js';
|
|
20
|
+
import { SimpleServiceSession } from '../base.js';
|
|
21
|
+
import { parseLoginFlowParams } from './base.js';
|
|
22
|
+
/**
|
|
23
|
+
* The path a cookie without a `Path` attribute applies to: the directory of the
|
|
24
|
+
* request path (RFC 6265 §5.1.4).
|
|
25
|
+
*/
|
|
26
|
+
function defaultCookiePath(responseUrl) {
|
|
27
|
+
const path = responseUrl.pathname;
|
|
28
|
+
if (!path.startsWith('/')) {
|
|
29
|
+
return '/';
|
|
30
|
+
}
|
|
31
|
+
const lastSeparatorIndex = path.lastIndexOf('/');
|
|
32
|
+
return lastSeparatorIndex === 0 ? '/' : path.slice(0, lastSeparatorIndex);
|
|
33
|
+
}
|
|
34
|
+
function isExpired(expiresAttribute) {
|
|
35
|
+
const expiresAt = Date.parse(expiresAttribute);
|
|
36
|
+
return !Number.isNaN(expiresAt) && expiresAt <= Date.now();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Parse one `Set-Cookie` header value, as sent by the response at
|
|
40
|
+
* `responseUrl`. Returns null when it is not a usable cookie definition at all.
|
|
41
|
+
*/
|
|
42
|
+
function parseSetCookieHeader(headerValue, responseUrl) {
|
|
43
|
+
const [nameValuePair = '', ...attributeParts] = headerValue.split(';');
|
|
44
|
+
const separatorIndex = nameValuePair.indexOf('=');
|
|
45
|
+
if (separatorIndex <= 0) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const name = nameValuePair.slice(0, separatorIndex).trim();
|
|
49
|
+
const value = nameValuePair.slice(separatorIndex + 1).trim();
|
|
50
|
+
let domain = responseUrl.hostname.toLowerCase();
|
|
51
|
+
let path = defaultCookiePath(responseUrl);
|
|
52
|
+
// An empty value is how a cookie is cleared without an explicit expiry.
|
|
53
|
+
let isDeletion = value === '';
|
|
54
|
+
for (const attributePart of attributeParts) {
|
|
55
|
+
const attributeSeparatorIndex = attributePart.indexOf('=');
|
|
56
|
+
const attributeName = (attributeSeparatorIndex === -1
|
|
57
|
+
? attributePart
|
|
58
|
+
: attributePart.slice(0, attributeSeparatorIndex))
|
|
59
|
+
.trim()
|
|
60
|
+
.toLowerCase();
|
|
61
|
+
const attributeValue = attributeSeparatorIndex === -1 ? '' : attributePart.slice(attributeSeparatorIndex + 1).trim();
|
|
62
|
+
if (attributeName === 'domain' && attributeValue !== '') {
|
|
63
|
+
domain = attributeValue.replace(/^\./, '').toLowerCase();
|
|
64
|
+
}
|
|
65
|
+
else if (attributeName === 'path' && attributeValue.startsWith('/')) {
|
|
66
|
+
path = attributeValue;
|
|
67
|
+
}
|
|
68
|
+
else if (attributeName === 'max-age' && Number(attributeValue) <= 0) {
|
|
69
|
+
isDeletion = true;
|
|
70
|
+
}
|
|
71
|
+
else if (attributeName === 'expires' && isExpired(attributeValue)) {
|
|
72
|
+
isDeletion = true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return { name, value, domain, path, isDeletion };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Whether a browser would send this cookie to the given URL: the URL's host is
|
|
79
|
+
* the cookie's domain or below it, and its path is under the cookie's path.
|
|
80
|
+
*/
|
|
81
|
+
function doesCookieApplyTo(cookie, url) {
|
|
82
|
+
const host = url.hostname.toLowerCase();
|
|
83
|
+
if (host !== cookie.domain && !host.endsWith(`.${cookie.domain}`)) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
const path = url.pathname === '' ? '/' : url.pathname;
|
|
87
|
+
return path.startsWith(cookie.path);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Identity of a cookie in the jar. The same name can be set more than once
|
|
91
|
+
* under different scopes, and a browser then sends all of them, so a cookie is
|
|
92
|
+
* only superseded by one of matching name, domain and path.
|
|
93
|
+
*/
|
|
94
|
+
function cookieScopeKey(cookie) {
|
|
95
|
+
return `${cookie.name}\n${cookie.domain}\n${cookie.path}`;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* The cookies that would be sent to one URL, built up from the `Set-Cookie`
|
|
99
|
+
* headers of the responses observed so far.
|
|
100
|
+
*
|
|
101
|
+
* Only cookies that apply to the jar's URL are kept, so cookies picked up along
|
|
102
|
+
* the way — from an identity provider on another domain, say — are discarded as
|
|
103
|
+
* they arrive.
|
|
104
|
+
*/
|
|
105
|
+
class CookieJar {
|
|
106
|
+
url;
|
|
107
|
+
cookiesByScope = new Map();
|
|
108
|
+
constructor(url) {
|
|
109
|
+
this.url = url;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Take in the `Set-Cookie` headers of one response: cookies it sets are
|
|
113
|
+
* recorded, and cookies it clears are dropped.
|
|
114
|
+
*/
|
|
115
|
+
accept(setCookieHeaderValues, responseUrl) {
|
|
116
|
+
for (const headerValue of setCookieHeaderValues) {
|
|
117
|
+
const cookie = parseSetCookieHeader(headerValue, responseUrl);
|
|
118
|
+
if (cookie === null || !doesCookieApplyTo(cookie, this.url)) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (cookie.isDeletion) {
|
|
122
|
+
this.cookiesByScope.delete(cookieScopeKey(cookie));
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
this.cookiesByScope.set(cookieScopeKey(cookie), cookie);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
has(name) {
|
|
130
|
+
return [...this.cookiesByScope.values()].some((cookie) => cookie.name === name);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The cookies of the given names. A name can appear more than once — set both
|
|
134
|
+
* host-only and domain-wide, say — and a browser sends every one of them.
|
|
135
|
+
*/
|
|
136
|
+
cookiesNamed(names) {
|
|
137
|
+
return [...this.cookiesByScope.values()]
|
|
138
|
+
.filter((cookie) => names.includes(cookie.name))
|
|
139
|
+
.map((cookie) => ({ name: cookie.name, value: cookie.value }));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Render cookies as the value of a single `Cookie` header.
|
|
144
|
+
*
|
|
145
|
+
* One header carrying every pair separated by `'; '` is the only portable
|
|
146
|
+
* form: RFC 6265 has the user agent send one `Cookie` header, and servers that
|
|
147
|
+
* see several header lines commonly read just the first.
|
|
148
|
+
*/
|
|
149
|
+
function formatCookieHeaderValue(cookies) {
|
|
150
|
+
return cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join('; ');
|
|
151
|
+
}
|
|
152
|
+
const CookieCaptureParamsSchema = z
|
|
153
|
+
.object({
|
|
154
|
+
/** Cookie names to capture. The login completes once all of them exist. */
|
|
155
|
+
cookieKeys: z.array(z.string().min(1)).min(1),
|
|
156
|
+
/**
|
|
157
|
+
* URL the cookies must apply to. Defaults to the service's login URL, which
|
|
158
|
+
* is right unless sign-in happens on a different host than the API.
|
|
159
|
+
*/
|
|
160
|
+
cookieUrl: z.string().url().optional(),
|
|
161
|
+
})
|
|
162
|
+
.strict();
|
|
163
|
+
/** Store captured cookies the way `latchkey auth set -H` would. */
|
|
164
|
+
function buildCookieCredentials(cookies) {
|
|
165
|
+
return new RawCurlCredentials(['-H', `Cookie: ${formatCookieHeaderValue(cookies)}`]);
|
|
166
|
+
}
|
|
167
|
+
function setCookieHeaderValues(headers) {
|
|
168
|
+
return headers
|
|
169
|
+
.filter((header) => header.name.toLowerCase() === 'set-cookie')
|
|
170
|
+
.map((header) => header.value);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* One run of the flow. A jar remembers the cookies as responses arrive; all
|
|
174
|
+
* this adds is which names the service asked for, and the rule that the login
|
|
175
|
+
* is done once every one of them has turned up.
|
|
176
|
+
*/
|
|
177
|
+
class CookieCaptureSession extends SimpleServiceSession {
|
|
178
|
+
jar;
|
|
179
|
+
cookieKeys;
|
|
180
|
+
constructor(service, appNamePrefix, cookieUrl, cookieKeys) {
|
|
181
|
+
super(service, appNamePrefix);
|
|
182
|
+
this.jar = new CookieJar(cookieUrl);
|
|
183
|
+
this.cookieKeys = cookieKeys;
|
|
184
|
+
}
|
|
185
|
+
async getApiCredentialsFromResponse(response) {
|
|
186
|
+
this.jar.accept(setCookieHeaderValues(await response.headersArray()), new URL(response.url()));
|
|
187
|
+
if (!this.cookieKeys.every((cookieKey) => this.jar.has(cookieKey))) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
return buildCookieCredentials(this.jar.cookiesNamed(this.cookieKeys));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* The flow. Its statics are the kind of automation — what `--login-flow`
|
|
195
|
+
* selects — and an instance is that kind configured with one service's
|
|
196
|
+
* parameters, ready to create a session per login.
|
|
197
|
+
*/
|
|
198
|
+
export class CookieCaptureLoginFlow {
|
|
199
|
+
/** Value of `--login-flow`. Not `name`, which every class already has. */
|
|
200
|
+
static flowName = 'cookie-capture';
|
|
201
|
+
static summary = 'Open the login URL and capture named session cookies as they are set.';
|
|
202
|
+
static details = [
|
|
203
|
+
'Parameters:',
|
|
204
|
+
' cookieKeys Names of the cookies to capture. Required, at least one. The',
|
|
205
|
+
' login finishes once every one of them has been set, and they',
|
|
206
|
+
' are stored together as a single "Cookie: a=1; b=2" header.',
|
|
207
|
+
' cookieUrl Full URL, including the scheme, that the cookies must apply',
|
|
208
|
+
' to. Defaults to the login URL. Set it when signing in happens',
|
|
209
|
+
' on a different host than the API.',
|
|
210
|
+
'',
|
|
211
|
+
'The cookies are read from the Set-Cookie headers of the responses that',
|
|
212
|
+
'arrive while the user signs in, so a cookie that only a page script sets is',
|
|
213
|
+
'not seen, and neither is one that an already signed-in session never sends',
|
|
214
|
+
'again.',
|
|
215
|
+
'',
|
|
216
|
+
'Example:',
|
|
217
|
+
' $ latchkey services register my-intranet \\',
|
|
218
|
+
' --base-api-url="https://intranet.example.com/api/" \\',
|
|
219
|
+
' --login-url="https://intranet.example.com/login" \\',
|
|
220
|
+
' --login-flow=cookie-capture \\',
|
|
221
|
+
' --login-flow-params=\'{"cookieKeys": ["sessionid", "csrftoken"]}\'',
|
|
222
|
+
].join('\n');
|
|
223
|
+
static paramsSchema = CookieCaptureParamsSchema;
|
|
224
|
+
params;
|
|
225
|
+
constructor(rawParams) {
|
|
226
|
+
this.params = parseLoginFlowParams(CookieCaptureLoginFlow, rawParams);
|
|
227
|
+
}
|
|
228
|
+
describe(loginUrl) {
|
|
229
|
+
const quotedKeys = this.params.cookieKeys.map((cookieKey) => `'${cookieKey}'`).join(', ');
|
|
230
|
+
return (`\`latchkey auth browser\` opens ${loginUrl} and stores the ${quotedKeys} ` +
|
|
231
|
+
`cookies of ${this.params.cookieUrl ?? loginUrl} as the credentials once they are set.`);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* The cookies are looked for wherever they would be sent: the page the login
|
|
235
|
+
* starts from, unless the parameters name somewhere else.
|
|
236
|
+
*/
|
|
237
|
+
createSession(service, appNamePrefix) {
|
|
238
|
+
return new CookieCaptureSession(service, appNamePrefix, new URL(this.params.cookieUrl ?? service.loginUrl), this.params.cookieKeys);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// TypeScript has no `static implements`, so this is where the class side of the
|
|
242
|
+
// flow is checked. The registry checks it again, but the error lands here.
|
|
243
|
+
CookieCaptureLoginFlow;
|
|
244
|
+
//# sourceMappingURL=cookieCapture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookieCapture.js","sourceRoot":"","sources":["../../../../../src/services/core/loginFlows/cookieCapture.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The list of generic browser login flows, and looking one up by the name
|
|
3
|
+
* `--login-flow` takes.
|
|
4
|
+
*
|
|
5
|
+
* This is the only module that knows which flows exist. What a flow *is* lives
|
|
6
|
+
* in `base`, which the flows themselves import; keeping the list separate is
|
|
7
|
+
* what stops that from being a cycle.
|
|
8
|
+
*/
|
|
9
|
+
import type { LoginFlow, LoginFlowClass } from './base.js';
|
|
10
|
+
export declare const LOGIN_FLOWS: readonly LoginFlowClass[];
|
|
11
|
+
export declare class UnknownLoginFlowError extends Error {
|
|
12
|
+
constructor(name: string);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Look up a flow class by the name `--login-flow` takes, and configure it with
|
|
16
|
+
* the given parameters.
|
|
17
|
+
*
|
|
18
|
+
* Throws {@link UnknownLoginFlowError}, or `LoginFlowParamsInvalidError` from
|
|
19
|
+
* the flow's own validation; callers decide what an unusable flow means for
|
|
20
|
+
* them (the CLI rejects the registration, loading a stored service drops just
|
|
21
|
+
* the flow).
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveLoginFlow(name: string, params: unknown): LoginFlow;
|
|
24
|
+
/**
|
|
25
|
+
* The reference documentation for every registered flow, for
|
|
26
|
+
* `latchkey services register --help`. Generated from the registry, so a flow
|
|
27
|
+
* added later documents itself without the CLI knowing anything about it.
|
|
28
|
+
*/
|
|
29
|
+
export declare function formatLoginFlowsHelp(): string;
|
|
30
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../../../src/services/core/loginFlows/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3D,eAAO,MAAM,WAAW,EAAE,SAAS,cAAc,EAA6B,CAAC;AAE/E,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,IAAI,EAAE,MAAM;CAOzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,SAAS,CAMzE;AASD;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAa7C"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The list of generic browser login flows, and looking one up by the name
|
|
3
|
+
* `--login-flow` takes.
|
|
4
|
+
*
|
|
5
|
+
* This is the only module that knows which flows exist. What a flow *is* lives
|
|
6
|
+
* in `base`, which the flows themselves import; keeping the list separate is
|
|
7
|
+
* what stops that from being a cycle.
|
|
8
|
+
*/
|
|
9
|
+
import { CookieCaptureLoginFlow } from './cookieCapture.js';
|
|
10
|
+
export const LOGIN_FLOWS = [CookieCaptureLoginFlow];
|
|
11
|
+
export class UnknownLoginFlowError extends Error {
|
|
12
|
+
constructor(name) {
|
|
13
|
+
super(`Unknown login flow '${name}'. Available flows: ` +
|
|
14
|
+
`${LOGIN_FLOWS.map((flowClass) => flowClass.flowName).join(', ')}.`);
|
|
15
|
+
this.name = 'UnknownLoginFlowError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Look up a flow class by the name `--login-flow` takes, and configure it with
|
|
20
|
+
* the given parameters.
|
|
21
|
+
*
|
|
22
|
+
* Throws {@link UnknownLoginFlowError}, or `LoginFlowParamsInvalidError` from
|
|
23
|
+
* the flow's own validation; callers decide what an unusable flow means for
|
|
24
|
+
* them (the CLI rejects the registration, loading a stored service drops just
|
|
25
|
+
* the flow).
|
|
26
|
+
*/
|
|
27
|
+
export function resolveLoginFlow(name, params) {
|
|
28
|
+
const flowClass = LOGIN_FLOWS.find((candidate) => candidate.flowName === name);
|
|
29
|
+
if (flowClass === undefined) {
|
|
30
|
+
throw new UnknownLoginFlowError(name);
|
|
31
|
+
}
|
|
32
|
+
return new flowClass(params);
|
|
33
|
+
}
|
|
34
|
+
function indent(text, spaces) {
|
|
35
|
+
return text
|
|
36
|
+
.split('\n')
|
|
37
|
+
.map((line) => (line === '' ? '' : `${spaces}${line}`))
|
|
38
|
+
.join('\n');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The reference documentation for every registered flow, for
|
|
42
|
+
* `latchkey services register --help`. Generated from the registry, so a flow
|
|
43
|
+
* added later documents itself without the CLI knowing anything about it.
|
|
44
|
+
*/
|
|
45
|
+
export function formatLoginFlowsHelp() {
|
|
46
|
+
const sections = LOGIN_FLOWS.map((flowClass) => ` ${flowClass.flowName}\n${indent(flowClass.summary, ' ')}\n\n` +
|
|
47
|
+
indent(flowClass.details, ' '));
|
|
48
|
+
return [
|
|
49
|
+
'Login flows:',
|
|
50
|
+
' Each login flow is configured by a JSON object supplied by',
|
|
51
|
+
' --login-flow-params.',
|
|
52
|
+
'',
|
|
53
|
+
...sections,
|
|
54
|
+
].join('\n');
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../../../src/services/core/loginFlows/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAG5D,MAAM,CAAC,MAAM,WAAW,GAA8B,CAAC,sBAAsB,CAAC,CAAC;AAE/E,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,IAAY;QACtB,KAAK,CACH,uBAAuB,IAAI,sBAAsB;YAC/C,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CACtE,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,MAAe;IAC5D,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC;IAC/E,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,MAAM,CAAC,IAAY,EAAE,MAAc;IAC1C,OAAO,IAAI;SACR,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI,EAAE,CAAC,CAAC;SACtD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAC9B,CAAC,SAAS,EAAE,EAAE,CACZ,KAAK,SAAS,CAAC,QAAQ,KAAK,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM;QACnE,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CACpC,CAAC;IACF,OAAO;QACL,cAAc;QACd,8DAA8D;QAC9D,wBAAwB;QACxB,EAAE;QACF,GAAG,QAAQ;KACZ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
|
@@ -3,10 +3,46 @@
|
|
|
3
3
|
* with a custom name and base API URL. Used for self-hosted instances.
|
|
4
4
|
*
|
|
5
5
|
* When no family service is provided, the registered service acts as a
|
|
6
|
-
* generic service that
|
|
6
|
+
* generic service that supports `latchkey auth set` for credentials, plus —
|
|
7
|
+
* if a login URL and a login flow were given — a browser login of its own.
|
|
7
8
|
*/
|
|
8
9
|
import { ApiCredentialStatus, type ApiCredentials } from '../../apiCredentials/base.js';
|
|
9
10
|
import { Service, type ServiceSession } from './base.js';
|
|
11
|
+
import type { LoginFlow } from './loginFlows/base.js';
|
|
12
|
+
/**
|
|
13
|
+
* Where a registered service gets its browser login, if anywhere. The two
|
|
14
|
+
* sources are mutually exclusive — a family service already brings its own
|
|
15
|
+
* login and credential shape — so they are alternatives rather than fields
|
|
16
|
+
* that happen not to be combined. Omitting the options entirely leaves the
|
|
17
|
+
* service with `latchkey auth set` only.
|
|
18
|
+
*
|
|
19
|
+
* The `never` markers are what make the exclusion stick: a plain union of the
|
|
20
|
+
* two shapes would still accept an object carrying both, because excess
|
|
21
|
+
* property checking against a union permits any property known to some member.
|
|
22
|
+
*/
|
|
23
|
+
export type RegisteredServiceOptions = {
|
|
24
|
+
/** Built-in service to use as a template, for self-hosted instances. */
|
|
25
|
+
readonly familyService: Service;
|
|
26
|
+
/** Page opened by `latchkey auth browser`, for families that support it. */
|
|
27
|
+
readonly loginUrl?: string;
|
|
28
|
+
readonly loginFlow?: never;
|
|
29
|
+
} | {
|
|
30
|
+
/** Generic browser login, already configured with its parameters. */
|
|
31
|
+
readonly loginFlow: LoginFlow;
|
|
32
|
+
/** Page the flow starts from. A flow has nowhere to begin without one. */
|
|
33
|
+
readonly loginUrl: string;
|
|
34
|
+
readonly familyService?: never;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Build options from values that are each independently optional, as they come
|
|
38
|
+
* out of the CLI and out of config.json.
|
|
39
|
+
*
|
|
40
|
+
* This is the one place where a family service and a login flow can meet, so it
|
|
41
|
+
* is also where their precedence is decided: the family wins, since its login
|
|
42
|
+
* and credential shape are what the rest of the service is built on. Callers
|
|
43
|
+
* that construct options directly are held to the exclusion by the type.
|
|
44
|
+
*/
|
|
45
|
+
export declare function buildRegisteredServiceOptions(familyService: Service | undefined, loginUrl: string | undefined, loginFlow: LoginFlow | undefined): RegisteredServiceOptions | undefined;
|
|
10
46
|
export declare class RegisteredService extends Service {
|
|
11
47
|
readonly name: string;
|
|
12
48
|
readonly displayName: string;
|
|
@@ -15,7 +51,7 @@ export declare class RegisteredService extends Service {
|
|
|
15
51
|
readonly info: string;
|
|
16
52
|
readonly credentialCheckCurlArguments: readonly string[];
|
|
17
53
|
private readonly familyService;
|
|
18
|
-
constructor(name: string, baseApiUrl: string,
|
|
54
|
+
constructor(name: string, baseApiUrl: string, options?: RegisteredServiceOptions);
|
|
19
55
|
getSession?(appNamePrefix: string): ServiceSession;
|
|
20
56
|
checkApiCredentials(): Promise<ApiCredentialStatus>;
|
|
21
57
|
getAccount(): Promise<string | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registered.d.ts","sourceRoot":"","sources":["../../../../src/services/core/registered.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"registered.d.ts","sourceRoot":"","sources":["../../../../src/services/core/registered.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,wBAAwB,GAChC;IACE,wEAAwE;IACxE,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,KAAK,CAAC;CAC5B,GACD;IACE,qEAAqE;IACrE,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC;CAChC,CAAC;AAEN;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,OAAO,GAAG,SAAS,EAClC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,SAAS,EAAE,SAAS,GAAG,SAAS,GAC/B,wBAAwB,GAAG,SAAS,CAQtC;AAED,qBAAa,iBAAkB,SAAQ,OAAO;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,4BAA4B,EAAE,SAAS,MAAM,EAAE,CAAC;IAEzD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;gBAExC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,wBAAwB;IAsCvE,UAAU,CAAC,CAAC,aAAa,EAAE,MAAM,GAAG,cAAc;IAElD,mBAAmB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAM5D,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAIpC,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAOzC,oBAAoB,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc;CAM7E"}
|
|
@@ -3,10 +3,29 @@
|
|
|
3
3
|
* with a custom name and base API URL. Used for self-hosted instances.
|
|
4
4
|
*
|
|
5
5
|
* When no family service is provided, the registered service acts as a
|
|
6
|
-
* generic service that
|
|
6
|
+
* generic service that supports `latchkey auth set` for credentials, plus —
|
|
7
|
+
* if a login URL and a login flow were given — a browser login of its own.
|
|
7
8
|
*/
|
|
8
9
|
import { ApiCredentialStatus } from '../../apiCredentials/base.js';
|
|
9
10
|
import { Service } from './base.js';
|
|
11
|
+
/**
|
|
12
|
+
* Build options from values that are each independently optional, as they come
|
|
13
|
+
* out of the CLI and out of config.json.
|
|
14
|
+
*
|
|
15
|
+
* This is the one place where a family service and a login flow can meet, so it
|
|
16
|
+
* is also where their precedence is decided: the family wins, since its login
|
|
17
|
+
* and credential shape are what the rest of the service is built on. Callers
|
|
18
|
+
* that construct options directly are held to the exclusion by the type.
|
|
19
|
+
*/
|
|
20
|
+
export function buildRegisteredServiceOptions(familyService, loginUrl, loginFlow) {
|
|
21
|
+
if (familyService !== undefined) {
|
|
22
|
+
return { familyService, loginUrl };
|
|
23
|
+
}
|
|
24
|
+
if (loginFlow !== undefined && loginUrl !== undefined) {
|
|
25
|
+
return { loginFlow, loginUrl };
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
10
29
|
export class RegisteredService extends Service {
|
|
11
30
|
name;
|
|
12
31
|
displayName;
|
|
@@ -15,8 +34,16 @@ export class RegisteredService extends Service {
|
|
|
15
34
|
info;
|
|
16
35
|
credentialCheckCurlArguments;
|
|
17
36
|
familyService;
|
|
18
|
-
constructor(name, baseApiUrl,
|
|
37
|
+
constructor(name, baseApiUrl, options) {
|
|
19
38
|
super();
|
|
39
|
+
const familyService = options?.familyService;
|
|
40
|
+
const loginUrl = options?.loginUrl;
|
|
41
|
+
// The options type rules out a flow without a page to open, and a flow
|
|
42
|
+
// alongside a family service, for TypeScript callers. This repeats the
|
|
43
|
+
// checks because latchkey is also consumed as a library from JavaScript.
|
|
44
|
+
const usableLoginFlow = options?.loginFlow !== undefined && loginUrl !== undefined && familyService === undefined
|
|
45
|
+
? { flow: options.loginFlow, loginUrl }
|
|
46
|
+
: undefined;
|
|
20
47
|
this.name = name;
|
|
21
48
|
this.displayName = name;
|
|
22
49
|
this.baseApiUrls = [baseApiUrl];
|
|
@@ -26,6 +53,11 @@ export class RegisteredService extends Service {
|
|
|
26
53
|
if (familyService !== undefined) {
|
|
27
54
|
this.info = `Self-hosted ${familyService.displayName} instance. ${familyService.info}`;
|
|
28
55
|
}
|
|
56
|
+
else if (usableLoginFlow !== undefined) {
|
|
57
|
+
this.info =
|
|
58
|
+
`Generic service. ${usableLoginFlow.flow.describe(usableLoginFlow.loginUrl)} ` +
|
|
59
|
+
'Alternatively, use `latchkey auth set` to supply credentials as curl arguments.';
|
|
60
|
+
}
|
|
29
61
|
else {
|
|
30
62
|
this.info =
|
|
31
63
|
'Generic service. Use `latchkey auth set` to supply credentials as curl arguments.';
|
|
@@ -33,6 +65,9 @@ export class RegisteredService extends Service {
|
|
|
33
65
|
if (loginUrl !== undefined && familyService?.getSession !== undefined) {
|
|
34
66
|
this.getSession = (appNamePrefix) => familyService.getSession(appNamePrefix);
|
|
35
67
|
}
|
|
68
|
+
else if (usableLoginFlow !== undefined) {
|
|
69
|
+
this.getSession = (appNamePrefix) => usableLoginFlow.flow.createSession(this, appNamePrefix);
|
|
70
|
+
}
|
|
36
71
|
}
|
|
37
72
|
checkApiCredentials() {
|
|
38
73
|
return Promise.resolve(ApiCredentialStatus.Unknown);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registered.js","sourceRoot":"","sources":["../../../../src/services/core/registered.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"registered.js","sourceRoot":"","sources":["../../../../src/services/core/registered.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
export { Service, ServiceSession, SimpleServiceSession, BrowserFollowupServiceSession, FollowupWork, buildFollowupSpinnerDetails, type LoginResult, } from './core/base.js';
|
|
5
5
|
export { LoginCancelledError, LoginFailedError, NoCurlCredentialsNotSupportedError, PrepareNotSupportedError, PrepareInputInvalidError, } from './core/base.js';
|
|
6
6
|
export { RegisteredService } from './core/registered.js';
|
|
7
|
+
export { LOGIN_FLOWS, UnknownLoginFlowError, formatLoginFlowsHelp, resolveLoginFlow, } from './core/loginFlows/registry.js';
|
|
8
|
+
export { LoginFlowParamsInvalidError, parseLoginFlowParams, type LoginFlow, type LoginFlowClass, } from './core/loginFlows/base.js';
|
|
9
|
+
export { CookieCaptureLoginFlow } from './core/loginFlows/cookieCapture.js';
|
|
7
10
|
export { Slack, SLACK } from './slack.js';
|
|
8
11
|
export { Discord, DISCORD } from './discord.js';
|
|
9
12
|
export { Github, GITHUB } from './github.js';
|
|
@@ -35,4 +38,5 @@ export { Coolify, COOLIFY } from './coolify.js';
|
|
|
35
38
|
export { Umami, UMAMI } from './umami.js';
|
|
36
39
|
export { Ramp, RAMP } from './ramp.js';
|
|
37
40
|
export { Todoist, TODOIST } from './todoist.js';
|
|
41
|
+
export { Ngrok, NGROK } from './ngrok.js';
|
|
38
42
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,OAAO,EACP,cAAc,EACd,oBAAoB,EACpB,6BAA6B,EAC7B,YAAY,EACZ,2BAA2B,EAC3B,KAAK,WAAW,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,kCAAkC,EAClC,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
export { Service, ServiceSession, SimpleServiceSession, BrowserFollowupServiceSession, FollowupWork, buildFollowupSpinnerDetails, } from './core/base.js';
|
|
5
5
|
export { LoginCancelledError, LoginFailedError, NoCurlCredentialsNotSupportedError, PrepareNotSupportedError, PrepareInputInvalidError, } from './core/base.js';
|
|
6
6
|
export { RegisteredService } from './core/registered.js';
|
|
7
|
+
export { LOGIN_FLOWS, UnknownLoginFlowError, formatLoginFlowsHelp, resolveLoginFlow, } from './core/loginFlows/registry.js';
|
|
8
|
+
export { LoginFlowParamsInvalidError, parseLoginFlowParams, } from './core/loginFlows/base.js';
|
|
9
|
+
export { CookieCaptureLoginFlow } from './core/loginFlows/cookieCapture.js';
|
|
7
10
|
export { Slack, SLACK } from './slack.js';
|
|
8
11
|
export { Discord, DISCORD } from './discord.js';
|
|
9
12
|
export { Github, GITHUB } from './github.js';
|
|
@@ -35,4 +38,5 @@ export { Coolify, COOLIFY } from './coolify.js';
|
|
|
35
38
|
export { Umami, UMAMI } from './umami.js';
|
|
36
39
|
export { Ramp, RAMP } from './ramp.js';
|
|
37
40
|
export { Todoist, TODOIST } from './todoist.js';
|
|
41
|
+
export { Ngrok, NGROK } from './ngrok.js';
|
|
38
42
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,OAAO,EACP,cAAc,EACd,oBAAoB,EACpB,6BAA6B,EAC7B,YAAY,EACZ,2BAA2B,GAE5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,kCAAkC,EAClC,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/services/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ngrok service implementation.
|
|
3
|
+
*
|
|
4
|
+
* ngrok issues personal API keys from its dashboard, and the key value is
|
|
5
|
+
* revealed exactly once at creation time (like Linear). We sign the user into
|
|
6
|
+
* the dashboard, create a fresh API key on their behalf, and read its value
|
|
7
|
+
* from the one-time reveal dialog.
|
|
8
|
+
*
|
|
9
|
+
* Every ngrok API request must carry two headers: the bearer API key and a
|
|
10
|
+
* constant `ngrok-version` header (https://ngrok.com/docs/api/#authentication).
|
|
11
|
+
* We therefore store the credential as raw curl arguments that inject both, so
|
|
12
|
+
* a plain `latchkey curl` to the ngrok API works without the caller having to
|
|
13
|
+
* remember the version header.
|
|
14
|
+
*/
|
|
15
|
+
import type { Response, BrowserContext } from 'playwright';
|
|
16
|
+
import { ApiCredentials } from '../apiCredentials/base.js';
|
|
17
|
+
import { Service, BrowserFollowupServiceSession, FollowupWork } from './core/base.js';
|
|
18
|
+
declare class NgrokServiceSession extends BrowserFollowupServiceSession {
|
|
19
|
+
protected readonly followupWork = FollowupWork.CreateApiToken;
|
|
20
|
+
private isLoggedIn;
|
|
21
|
+
onResponse(response: Response): void;
|
|
22
|
+
protected isLoginComplete(): boolean;
|
|
23
|
+
protected performBrowserFollowup(context: BrowserContext, _oldCredentials?: ApiCredentials): Promise<ApiCredentials | null>;
|
|
24
|
+
}
|
|
25
|
+
export declare class Ngrok extends Service {
|
|
26
|
+
readonly name = "ngrok";
|
|
27
|
+
readonly displayName = "ngrok";
|
|
28
|
+
readonly baseApiUrls: readonly ["https://api.ngrok.com/"];
|
|
29
|
+
readonly loginUrl = "https://dashboard.ngrok.com/login";
|
|
30
|
+
readonly info = "https://ngrok.com/docs/api/";
|
|
31
|
+
readonly credentialCheckCurlArguments: readonly ["https://api.ngrok.com/api_keys"];
|
|
32
|
+
setCredentialsExample(serviceName: string): string;
|
|
33
|
+
getAccount(_apiCredentials: ApiCredentials): Promise<string | null>;
|
|
34
|
+
getSession(appNamePrefix: string): NgrokServiceSession;
|
|
35
|
+
}
|
|
36
|
+
export declare const NGROK: Ngrok;
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=ngrok.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ngrok.d.ts","sourceRoot":"","sources":["../../../src/services/ngrok.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAsB,MAAM,2BAA2B,CAAC;AAE/E,OAAO,EACL,OAAO,EACP,6BAA6B,EAC7B,YAAY,EAEb,MAAM,gBAAgB,CAAC;AAkCxB,cAAM,mBAAoB,SAAQ,6BAA6B;IAC7D,SAAS,CAAC,QAAQ,CAAC,YAAY,+BAA+B;IAC9D,OAAO,CAAC,UAAU,CAAS;IAE3B,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IA4BpC,SAAS,CAAC,eAAe,IAAI,OAAO;cAIpB,sBAAsB,CACpC,OAAO,EAAE,cAAc,EACvB,eAAe,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;CAkClC;AAED,qBAAa,KAAM,SAAQ,OAAO;IAChC,QAAQ,CAAC,IAAI,WAAW;IACxB,QAAQ,CAAC,WAAW,WAAW;IAC/B,QAAQ,CAAC,WAAW,sCAAiC;IACrD,QAAQ,CAAC,QAAQ,uCAAmB;IACpC,QAAQ,CAAC,IAAI,iCAAiC;IAI9C,QAAQ,CAAC,4BAA4B,8CAA+C;IAEpF,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAMzC,UAAU,CAAC,eAAe,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAInE,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,mBAAmB;CAGhE;AAED,eAAO,MAAM,KAAK,OAAc,CAAC"}
|