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.
Files changed (71) hide show
  1. package/README.md +2 -1
  2. package/dist/skills/generic/latchkey/SKILL.md +1 -1
  3. package/dist/skills/openclaw/latchkey/SKILL.md +1 -1
  4. package/dist/src/apiCredentials/serialization.d.ts +21 -0
  5. package/dist/src/apiCredentials/serialization.d.ts.map +1 -1
  6. package/dist/src/apiCredentials/serialization.js +7 -0
  7. package/dist/src/apiCredentials/serialization.js.map +1 -1
  8. package/dist/src/cliCommands.d.ts.map +1 -1
  9. package/dist/src/cliCommands.js +91 -7
  10. package/dist/src/cliCommands.js.map +1 -1
  11. package/dist/src/configDataStore.d.ts +18 -0
  12. package/dist/src/configDataStore.d.ts.map +1 -1
  13. package/dist/src/configDataStore.js +10 -0
  14. package/dist/src/configDataStore.js.map +1 -1
  15. package/dist/src/serviceRegistry.d.ts.map +1 -1
  16. package/dist/src/serviceRegistry.js +27 -3
  17. package/dist/src/serviceRegistry.js.map +1 -1
  18. package/dist/src/services/aws.d.ts.map +1 -1
  19. package/dist/src/services/aws.js +1 -2
  20. package/dist/src/services/aws.js.map +1 -1
  21. package/dist/src/services/core/base.d.ts +25 -3
  22. package/dist/src/services/core/base.d.ts.map +1 -1
  23. package/dist/src/services/core/base.js +32 -10
  24. package/dist/src/services/core/base.js.map +1 -1
  25. package/dist/src/services/core/loginFlows/base.d.ts +75 -0
  26. package/dist/src/services/core/loginFlows/base.d.ts.map +1 -0
  27. package/dist/src/services/core/loginFlows/base.js +47 -0
  28. package/dist/src/services/core/loginFlows/base.js.map +1 -0
  29. package/dist/src/services/core/loginFlows/cookieCapture.d.ts +55 -0
  30. package/dist/src/services/core/loginFlows/cookieCapture.d.ts.map +1 -0
  31. package/dist/src/services/core/loginFlows/cookieCapture.js +244 -0
  32. package/dist/src/services/core/loginFlows/cookieCapture.js.map +1 -0
  33. package/dist/src/services/core/loginFlows/registry.d.ts +30 -0
  34. package/dist/src/services/core/loginFlows/registry.d.ts.map +1 -0
  35. package/dist/src/services/core/loginFlows/registry.js +56 -0
  36. package/dist/src/services/core/loginFlows/registry.js.map +1 -0
  37. package/dist/src/services/core/registered.d.ts +38 -2
  38. package/dist/src/services/core/registered.d.ts.map +1 -1
  39. package/dist/src/services/core/registered.js +37 -2
  40. package/dist/src/services/core/registered.js.map +1 -1
  41. package/dist/src/services/index.d.ts +4 -0
  42. package/dist/src/services/index.d.ts.map +1 -1
  43. package/dist/src/services/index.js +4 -0
  44. package/dist/src/services/index.js.map +1 -1
  45. package/dist/src/services/ngrok.d.ts +38 -0
  46. package/dist/src/services/ngrok.d.ts.map +1 -0
  47. package/dist/src/services/ngrok.js +129 -0
  48. package/dist/src/services/ngrok.js.map +1 -0
  49. package/dist/src/services/zoom.d.ts +118 -5
  50. package/dist/src/services/zoom.d.ts.map +1 -1
  51. package/dist/src/services/zoom.js +692 -7
  52. package/dist/src/services/zoom.js.map +1 -1
  53. package/dist/src/version.d.ts +1 -1
  54. package/dist/src/version.js +1 -1
  55. package/dist/tests/apiCredentials.test.js +5 -0
  56. package/dist/tests/apiCredentials.test.js.map +1 -1
  57. package/dist/tests/cli.test.js +178 -2
  58. package/dist/tests/cli.test.js.map +1 -1
  59. package/dist/tests/cookieCapture.test.d.ts +10 -0
  60. package/dist/tests/cookieCapture.test.d.ts.map +1 -0
  61. package/dist/tests/cookieCapture.test.js +221 -0
  62. package/dist/tests/cookieCapture.test.js.map +1 -0
  63. package/dist/tests/serviceRegistry.test.js +29 -8
  64. package/dist/tests/serviceRegistry.test.js.map +1 -1
  65. package/dist/tests/servicesAgainstRecordings.test.js +13 -11
  66. package/dist/tests/servicesAgainstRecordings.test.js.map +1 -1
  67. package/dist/tests/zoom.test.d.ts +2 -0
  68. package/dist/tests/zoom.test.d.ts.map +1 -0
  69. package/dist/tests/zoom.test.js +110 -0
  70. package/dist/tests/zoom.test.js.map +1 -0
  71. 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 only supports `latchkey auth set` for credentials.
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, familyService?: Service, loginUrl?: 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;;;;;;GAMG;AAEH,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAEzD,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,aAAa,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM;IAqB/E,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"}
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 only supports `latchkey auth set` for credentials.
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, familyService, loginUrl) {
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;;;;;;GAMG;AAEH,OAAO,EAAE,mBAAmB,EAAuB,MAAM,8BAA8B,CAAC;AACxF,OAAO,EAAE,OAAO,EAAuB,MAAM,WAAW,CAAC;AAEzD,MAAM,OAAO,iBAAkB,SAAQ,OAAO;IACnC,IAAI,CAAS;IACb,WAAW,CAAS;IACpB,WAAW,CAAoB;IAC/B,QAAQ,CAAS;IACjB,IAAI,CAAS;IACb,4BAA4B,CAAoB;IAExC,aAAa,CAAsB;IAEpD,YAAY,IAAY,EAAE,UAAkB,EAAE,aAAuB,EAAE,QAAiB;QACtF,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,WAAW,GAAG,CAAC,UAAU,CAAC,CAAC;QAChC,IAAI,CAAC,QAAQ,GAAG,QAAQ,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,4BAA4B,GAAG,EAAE,CAAC;QACvC,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QAEnC,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,IAAI,GAAG,eAAe,aAAa,CAAC,WAAW,cAAc,aAAa,CAAC,IAAI,EAAE,CAAC;QACzF,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI;gBACP,mFAAmF,CAAC;QACxF,CAAC;QAED,IAAI,QAAQ,KAAK,SAAS,IAAI,aAAa,EAAE,UAAU,KAAK,SAAS,EAAE,CAAC;YACtE,IAAI,CAAC,UAAU,GAAG,CAAC,aAAqB,EAAE,EAAE,CAAC,aAAa,CAAC,UAAW,CAAC,aAAa,CAAC,CAAC;QACxF,CAAC;IACH,CAAC;IAIQ,mBAAmB;QAC1B,OAAO,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACtD,CAAC;IAED,wEAAwE;IACxE,2DAA2D;IAC3D,UAAU;QACR,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED,qBAAqB,CAAC,WAAmB;QACvC,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC,aAAa,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,qBAAqB,WAAW,qCAAqC,CAAC;IAC/E,CAAC;IAEQ,oBAAoB,CAAC,UAA6B;QACzD,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC,aAAa,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO,KAAK,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC;IAChD,CAAC;CACF"}
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;AAEzD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,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;AAEzD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
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;AACzD,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,2BAA2B,EAC3B,oBAAoB,GAGrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAE5E,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
@@ -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"}