@rigkit/provider-freestyle 0.2.7 → 0.2.9
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 -2
- package/package.json +4 -4
- package/src/host-auth.test.ts +119 -10
- package/src/host-auth.ts +50 -26
- package/src/index.ts +24 -19
- package/src/version.ts +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,6 @@ This package supplies:
|
|
|
12
12
|
- Freestyle SDK exports like `VmSpec` and `VmBaseImage`, so configs use one SDK instance for specs and clients
|
|
13
13
|
- Freestyle-specific JSON state helpers backed by Rigkit provider storage
|
|
14
14
|
|
|
15
|
-
Pass
|
|
15
|
+
Pass `console.log` to Freestyle SDK calls that accept `logger` to stream SDK progress into the CLI. Console output inside a task handler is intercepted by the Rigkit runtime and emitted as leveled `log.output` events.
|
|
16
16
|
|
|
17
|
-
By default the provider authenticates through a browser login and stores Freestyle credentials in Rigkit's provider host storage, outside project `.rigkit/state.sqlite`. Pass `
|
|
17
|
+
By default the provider authenticates through a browser login and stores Freestyle credentials in Rigkit's provider host storage, outside project `.rigkit/state.sqlite`. Pass `freestyle.provider({ apiKey })` or `freestyle.provider(apiKey)` to use API-key auth instead.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigkit/provider-freestyle",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"zod": "^4",
|
|
20
|
-
"@rigkit/sdk": "0.2.
|
|
21
|
-
"@rigkit/
|
|
22
|
-
"@rigkit/
|
|
20
|
+
"@rigkit/sdk": "0.2.9",
|
|
21
|
+
"@rigkit/engine": "0.2.9",
|
|
22
|
+
"@rigkit/provider-cmux": "0.2.9"
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
25
|
"freestyle": "^0.1.51"
|
package/src/host-auth.test.ts
CHANGED
|
@@ -7,9 +7,10 @@ import type {
|
|
|
7
7
|
WorkflowProviderController,
|
|
8
8
|
WorkflowEvent,
|
|
9
9
|
} from "@rigkit/engine";
|
|
10
|
-
import { FREESTYLE_PROVIDER_ID, freestyleProviderPlugin } from "./index.ts";
|
|
10
|
+
import { FREESTYLE_PROVIDER_ID, freestyle, freestyleProviderPlugin } from "./index.ts";
|
|
11
11
|
import { createFreestyleProxyFetch } from "./host-auth.ts";
|
|
12
12
|
import type { FreestyleRuntime } from "./provider.ts";
|
|
13
|
+
import { RIGKIT_PROVIDER_FREESTYLE_VERSION } from "./version.ts";
|
|
13
14
|
|
|
14
15
|
const originalFreestyleApiKey = process.env.FREESTYLE_API_KEY;
|
|
15
16
|
const originalFreestyleTeamId = process.env.FREESTYLE_TEAM_ID;
|
|
@@ -20,19 +21,54 @@ afterEach(() => {
|
|
|
20
21
|
});
|
|
21
22
|
|
|
22
23
|
describe("Freestyle provider host auth", () => {
|
|
24
|
+
test("accepts an API key as the provider shorthand", () => {
|
|
25
|
+
expect(freestyle.provider("shorthand-api-key").config).toEqual({
|
|
26
|
+
apiKey: "shorthand-api-key",
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("rejects the old nested auth config shape", async () => {
|
|
31
|
+
const projectStorage = new MemoryProviderStorage(FREESTYLE_PROVIDER_ID);
|
|
32
|
+
const hostStorage = new MemoryProviderStorage(FREESTYLE_PROVIDER_ID);
|
|
33
|
+
|
|
34
|
+
await expect(freestyleProviderPlugin.createProvider({
|
|
35
|
+
provider: {
|
|
36
|
+
providerId: FREESTYLE_PROVIDER_ID,
|
|
37
|
+
config: {
|
|
38
|
+
auth: { apiKey: "nested-api-key" },
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
storage: projectStorage,
|
|
42
|
+
hostStorage,
|
|
43
|
+
local: { open: async () => {} },
|
|
44
|
+
})).rejects.toThrow("Invalid Freestyle provider config");
|
|
45
|
+
});
|
|
46
|
+
|
|
23
47
|
test("uses explicit API-key auth and stores identity tokens in host storage", async () => {
|
|
24
48
|
process.env.FREESTYLE_API_KEY = "ignored-env-api-key";
|
|
25
49
|
delete process.env.FREESTYLE_TEAM_ID;
|
|
26
50
|
|
|
27
51
|
const projectStorage = new MemoryProviderStorage(FREESTYLE_PROVIDER_ID);
|
|
28
52
|
const hostStorage = new MemoryProviderStorage(FREESTYLE_PROVIDER_ID);
|
|
29
|
-
const requests: Array<{
|
|
53
|
+
const requests: Array<{
|
|
54
|
+
url: string;
|
|
55
|
+
method: string;
|
|
56
|
+
authorization: string | null;
|
|
57
|
+
rigkit: string | null;
|
|
58
|
+
rigkitVersion: string | null;
|
|
59
|
+
}> = [];
|
|
30
60
|
const previousFetch = globalThis.fetch;
|
|
31
61
|
globalThis.fetch = testFetch((resource, init) => {
|
|
32
62
|
const url = resourceUrl(resource);
|
|
33
63
|
const method = init?.method ?? "GET";
|
|
34
|
-
const
|
|
35
|
-
requests.push({
|
|
64
|
+
const headers = new Headers(init?.headers);
|
|
65
|
+
requests.push({
|
|
66
|
+
url: url.href,
|
|
67
|
+
method,
|
|
68
|
+
authorization: headers.get("authorization"),
|
|
69
|
+
rigkit: headers.get("x-rigkit"),
|
|
70
|
+
rigkitVersion: headers.get("x-rigkit-version"),
|
|
71
|
+
});
|
|
36
72
|
if (url.pathname === "/identity/v1/identities" && method === "POST") {
|
|
37
73
|
return Response.json({ id: "identity-api-key" });
|
|
38
74
|
}
|
|
@@ -47,7 +83,7 @@ describe("Freestyle provider host auth", () => {
|
|
|
47
83
|
provider: {
|
|
48
84
|
providerId: FREESTYLE_PROVIDER_ID,
|
|
49
85
|
config: {
|
|
50
|
-
|
|
86
|
+
apiKey: "object-api-key",
|
|
51
87
|
},
|
|
52
88
|
},
|
|
53
89
|
storage: projectStorage,
|
|
@@ -72,11 +108,15 @@ describe("Freestyle provider host auth", () => {
|
|
|
72
108
|
url: "https://api.freestyle.sh/identity/v1/identities",
|
|
73
109
|
method: "POST",
|
|
74
110
|
authorization: "Bearer object-api-key",
|
|
111
|
+
rigkit: "true",
|
|
112
|
+
rigkitVersion: RIGKIT_PROVIDER_FREESTYLE_VERSION,
|
|
75
113
|
},
|
|
76
114
|
{
|
|
77
115
|
url: "https://api.freestyle.sh/identity/v1/identities/identity-api-key/tokens",
|
|
78
116
|
method: "POST",
|
|
79
117
|
authorization: "Bearer object-api-key",
|
|
118
|
+
rigkit: "true",
|
|
119
|
+
rigkitVersion: RIGKIT_PROVIDER_FREESTYLE_VERSION,
|
|
80
120
|
},
|
|
81
121
|
]);
|
|
82
122
|
} finally {
|
|
@@ -122,9 +162,7 @@ describe("Freestyle provider host auth", () => {
|
|
|
122
162
|
provider: {
|
|
123
163
|
providerId: FREESTYLE_PROVIDER_ID,
|
|
124
164
|
config: {
|
|
125
|
-
|
|
126
|
-
teamId: "team_123",
|
|
127
|
-
},
|
|
165
|
+
teamId: "team_123",
|
|
128
166
|
},
|
|
129
167
|
},
|
|
130
168
|
storage: projectStorage,
|
|
@@ -160,7 +198,10 @@ describe("Freestyle provider host auth", () => {
|
|
|
160
198
|
teamId: "team_123",
|
|
161
199
|
path: "identity/v1/identities",
|
|
162
200
|
method: "POST",
|
|
163
|
-
headers: expect.
|
|
201
|
+
headers: expect.objectContaining({
|
|
202
|
+
"x-rigkit": "true",
|
|
203
|
+
"x-rigkit-version": RIGKIT_PROVIDER_FREESTYLE_VERSION,
|
|
204
|
+
}),
|
|
164
205
|
},
|
|
165
206
|
},
|
|
166
207
|
{
|
|
@@ -169,7 +210,10 @@ describe("Freestyle provider host auth", () => {
|
|
|
169
210
|
teamId: "team_123",
|
|
170
211
|
path: "identity/v1/identities/identity-browser/tokens",
|
|
171
212
|
method: "POST",
|
|
172
|
-
headers: expect.
|
|
213
|
+
headers: expect.objectContaining({
|
|
214
|
+
"x-rigkit": "true",
|
|
215
|
+
"x-rigkit-version": RIGKIT_PROVIDER_FREESTYLE_VERSION,
|
|
216
|
+
}),
|
|
173
217
|
},
|
|
174
218
|
},
|
|
175
219
|
]);
|
|
@@ -258,6 +302,8 @@ describe("Freestyle provider proxy fetch", () => {
|
|
|
258
302
|
const url = resourceUrl(resource);
|
|
259
303
|
expect(url.href).toBe("https://dash.freestyle.sh/api/proxy/request");
|
|
260
304
|
expect(init?.method).toBe("POST");
|
|
305
|
+
expect(new Headers(init?.headers).get("x-rigkit")).toBe("true");
|
|
306
|
+
expect(new Headers(init?.headers).get("x-rigkit-version")).toBe(RIGKIT_PROVIDER_FREESTYLE_VERSION);
|
|
261
307
|
|
|
262
308
|
const body = JSON.parse(String(init?.body));
|
|
263
309
|
expect(body).toMatchObject({
|
|
@@ -266,6 +312,10 @@ describe("Freestyle provider proxy fetch", () => {
|
|
|
266
312
|
teamId: "team_123",
|
|
267
313
|
path: "v1/vms",
|
|
268
314
|
method: "POST",
|
|
315
|
+
headers: {
|
|
316
|
+
"x-rigkit": "true",
|
|
317
|
+
"x-rigkit-version": RIGKIT_PROVIDER_FREESTYLE_VERSION,
|
|
318
|
+
},
|
|
269
319
|
},
|
|
270
320
|
});
|
|
271
321
|
|
|
@@ -290,6 +340,65 @@ describe("Freestyle provider proxy fetch", () => {
|
|
|
290
340
|
status: "pending",
|
|
291
341
|
});
|
|
292
342
|
});
|
|
343
|
+
|
|
344
|
+
test("preserves proxy error details for run logs", async () => {
|
|
345
|
+
const proxyFetch = createFreestyleProxyFetch({
|
|
346
|
+
dashboardUrl: "https://dash.freestyle.sh",
|
|
347
|
+
accessToken: "stack-access-token",
|
|
348
|
+
teamId: "team_123",
|
|
349
|
+
fetch: testFetch(async () =>
|
|
350
|
+
Response.json({
|
|
351
|
+
error: "VM setup failed",
|
|
352
|
+
requestId: "req_123",
|
|
353
|
+
logs: ["failed to boot base image"],
|
|
354
|
+
accessToken: "secret-token",
|
|
355
|
+
}, { status: 500 })
|
|
356
|
+
),
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
const response = await proxyFetch("https://api.freestyle.sh/v1/vms", {
|
|
360
|
+
method: "POST",
|
|
361
|
+
body: "{}",
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
expect(response.status).toBe(500);
|
|
365
|
+
await expect(response.json()).resolves.toEqual({
|
|
366
|
+
code: "INTERNAL_ERROR",
|
|
367
|
+
message: "VM setup failed",
|
|
368
|
+
details: {
|
|
369
|
+
error: "VM setup failed",
|
|
370
|
+
requestId: "req_123",
|
|
371
|
+
logs: ["failed to boot base image"],
|
|
372
|
+
accessToken: "[redacted]",
|
|
373
|
+
},
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
test("redacts sensitive fields on coded proxy errors", async () => {
|
|
378
|
+
const proxyFetch = createFreestyleProxyFetch({
|
|
379
|
+
dashboardUrl: "https://dash.freestyle.sh",
|
|
380
|
+
accessToken: "stack-access-token",
|
|
381
|
+
teamId: "team_123",
|
|
382
|
+
fetch: testFetch(async () =>
|
|
383
|
+
Response.json({
|
|
384
|
+
code: "INTERNAL_ERROR",
|
|
385
|
+
message: "Internal server error",
|
|
386
|
+
requestId: "req_123",
|
|
387
|
+
accessToken: "secret-token",
|
|
388
|
+
}, { status: 500 })
|
|
389
|
+
),
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
const response = await proxyFetch("https://api.freestyle.sh/v1/vms");
|
|
393
|
+
|
|
394
|
+
expect(response.status).toBe(500);
|
|
395
|
+
await expect(response.json()).resolves.toEqual({
|
|
396
|
+
code: "INTERNAL_ERROR",
|
|
397
|
+
message: "Internal server error",
|
|
398
|
+
requestId: "req_123",
|
|
399
|
+
accessToken: "[redacted]",
|
|
400
|
+
});
|
|
401
|
+
});
|
|
293
402
|
});
|
|
294
403
|
|
|
295
404
|
class MemoryProviderStorage implements ProviderStorage {
|
package/src/host-auth.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { LocalWorkspaceRuntime, ProviderStorage } from "@rigkit/engine";
|
|
|
4
4
|
import type { JsonValue } from "@rigkit/sdk";
|
|
5
5
|
import { freestyleIdentityId, freestyleToken, freestyleTokenId } from "./auth.ts";
|
|
6
6
|
import { createFreestyleStore } from "./store.ts";
|
|
7
|
+
import { RIGKIT_PROVIDER_FREESTYLE_VERSION } from "./version.ts";
|
|
7
8
|
|
|
8
9
|
const DEFAULT_STACK_API_URL = "https://api.stack-auth.com";
|
|
9
10
|
const DEFAULT_STACK_APP_URL = "https://dash.freestyle.sh";
|
|
@@ -11,17 +12,15 @@ const DEFAULT_STACK_PROJECT_ID = "0edf478c-f123-46fb-818f-34c0024a9f35";
|
|
|
11
12
|
const DEFAULT_STACK_PUBLISHABLE_CLIENT_KEY = "pck_h2aft7g9pqjzrkdnzs199h1may5wjtdtdxeex7m2wzp1r";
|
|
12
13
|
const DEFAULT_CLI_AUTH_TIMEOUT_MILLIS = 10 * 60 * 1000;
|
|
13
14
|
const DEFAULT_POLL_INTERVAL_MILLIS = 2000;
|
|
15
|
+
const RIGKIT_HEADER = "x-rigkit";
|
|
16
|
+
const RIGKIT_VERSION_HEADER = "x-rigkit-version";
|
|
14
17
|
|
|
15
|
-
export type
|
|
18
|
+
export type FreestyleProviderConfig = {
|
|
16
19
|
apiKey?: string;
|
|
17
20
|
profile?: string;
|
|
18
21
|
teamId?: string;
|
|
19
22
|
apiUrl?: string;
|
|
20
23
|
dashboardUrl?: string;
|
|
21
|
-
stackApiUrl?: string;
|
|
22
|
-
stackAppUrl?: string;
|
|
23
|
-
stackProjectId?: string;
|
|
24
|
-
stackPublishableClientKey?: string;
|
|
25
24
|
};
|
|
26
25
|
|
|
27
26
|
export type FreestyleAuthenticatedClient = {
|
|
@@ -32,7 +31,7 @@ export type FreestyleAuthenticatedClient = {
|
|
|
32
31
|
};
|
|
33
32
|
|
|
34
33
|
type CreateFreestyleAuthenticatedClientInput = {
|
|
35
|
-
|
|
34
|
+
config?: FreestyleProviderConfig;
|
|
36
35
|
hostStorage: ProviderStorage;
|
|
37
36
|
local: LocalWorkspaceRuntime;
|
|
38
37
|
fetch?: typeof fetch;
|
|
@@ -119,16 +118,16 @@ export function createFreestyleProxyFetch(input: {
|
|
|
119
118
|
const path = `${url.pathname}${url.search}`.replace(/^\/+/, "");
|
|
120
119
|
const proxyResponse = await fetchFn(`${dashboardUrl}/api/proxy/request`, {
|
|
121
120
|
method: "POST",
|
|
122
|
-
headers: {
|
|
121
|
+
headers: withRigkitHeaders({
|
|
123
122
|
"Content-Type": "application/json",
|
|
124
|
-
},
|
|
123
|
+
}),
|
|
125
124
|
body: JSON.stringify({
|
|
126
125
|
data: {
|
|
127
126
|
accessToken: input.accessToken,
|
|
128
127
|
teamId: input.teamId,
|
|
129
128
|
path,
|
|
130
129
|
method: init?.method ?? "GET",
|
|
131
|
-
headers:
|
|
130
|
+
headers: Object.fromEntries(withRigkitHeaders(init?.headers).entries()),
|
|
132
131
|
body: init?.body ? String(init.body) : undefined,
|
|
133
132
|
},
|
|
134
133
|
}),
|
|
@@ -162,9 +161,20 @@ export function createFreestyleProxyFetch(input: {
|
|
|
162
161
|
}) as typeof fetch;
|
|
163
162
|
}
|
|
164
163
|
|
|
164
|
+
export function createFreestyleSdkFetch(fetchFn: typeof fetch = globalThis.fetch): typeof fetch {
|
|
165
|
+
const rigkitFetch = (async (resource, init) =>
|
|
166
|
+
await fetchFn(resource, {
|
|
167
|
+
...init,
|
|
168
|
+
headers: withRigkitHeaders(init?.headers),
|
|
169
|
+
})) as typeof fetch;
|
|
170
|
+
return Object.assign(rigkitFetch, {
|
|
171
|
+
preconnect: fetchFn.preconnect?.bind(fetchFn) ?? (() => {}),
|
|
172
|
+
}) as typeof fetch;
|
|
173
|
+
}
|
|
174
|
+
|
|
165
175
|
async function resolveClientAuth(input: CreateFreestyleAuthenticatedClientInput): Promise<ResolvedClientAuth> {
|
|
166
|
-
const apiKey = nonEmpty(input.
|
|
167
|
-
const apiUrl = nonEmpty(input.
|
|
176
|
+
const apiKey = nonEmpty(input.config?.apiKey);
|
|
177
|
+
const apiUrl = nonEmpty(input.config?.apiUrl) ?? nonEmpty(process.env.FREESTYLE_API_URL);
|
|
168
178
|
const fetchFn = input.fetch ?? globalThis.fetch;
|
|
169
179
|
|
|
170
180
|
if (apiKey) {
|
|
@@ -172,13 +182,13 @@ async function resolveClientAuth(input: CreateFreestyleAuthenticatedClientInput)
|
|
|
172
182
|
client: new Freestyle({
|
|
173
183
|
apiKey,
|
|
174
184
|
...(apiUrl ? { baseUrl: apiUrl } : {}),
|
|
175
|
-
fetch: fetchFn,
|
|
185
|
+
fetch: createFreestyleSdkFetch(fetchFn),
|
|
176
186
|
}),
|
|
177
187
|
identityKey: `api-key:${fingerprint({ apiUrl: apiUrl ?? "default", apiKey })}`,
|
|
178
188
|
};
|
|
179
189
|
}
|
|
180
190
|
|
|
181
|
-
const stack = resolveStackAuthConfig(input.
|
|
191
|
+
const stack = resolveStackAuthConfig(input.config);
|
|
182
192
|
const stackStateKey = stackAuthStateKey(stack);
|
|
183
193
|
const stored = readStackAuthState(input.hostStorage.get(stackStateKey)?.value);
|
|
184
194
|
const refreshed = await resolveStackAccessToken({
|
|
@@ -192,7 +202,7 @@ async function resolveClientAuth(input: CreateFreestyleAuthenticatedClientInput)
|
|
|
192
202
|
pollIntervalMs: input.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MILLIS,
|
|
193
203
|
});
|
|
194
204
|
const teamId = await resolveTeamId({
|
|
195
|
-
configuredTeamId: input.
|
|
205
|
+
configuredTeamId: input.config?.teamId,
|
|
196
206
|
stored: readStackAuthState(input.hostStorage.get(stackStateKey)?.value) ?? stored,
|
|
197
207
|
accessToken: refreshed.accessToken,
|
|
198
208
|
config: stack,
|
|
@@ -222,7 +232,7 @@ async function resolveClientAuth(input: CreateFreestyleAuthenticatedClientInput)
|
|
|
222
232
|
};
|
|
223
233
|
}
|
|
224
234
|
|
|
225
|
-
function resolveStackAuthConfig(auth:
|
|
235
|
+
function resolveStackAuthConfig(auth: FreestyleProviderConfig | undefined): StackAuthConfig {
|
|
226
236
|
const dashboardUrl = trimTrailingSlash(
|
|
227
237
|
nonEmpty(auth?.dashboardUrl) ??
|
|
228
238
|
nonEmpty(process.env.FREESTYLE_DASHBOARD_URL) ??
|
|
@@ -230,25 +240,21 @@ function resolveStackAuthConfig(auth: FreestyleProviderAuthConfig | undefined):
|
|
|
230
240
|
);
|
|
231
241
|
return {
|
|
232
242
|
stackApiUrl: trimTrailingSlash(
|
|
233
|
-
nonEmpty(
|
|
234
|
-
nonEmpty(process.env.FREESTYLE_STACK_API_URL) ??
|
|
243
|
+
nonEmpty(process.env.FREESTYLE_STACK_API_URL) ??
|
|
235
244
|
DEFAULT_STACK_API_URL,
|
|
236
245
|
),
|
|
237
246
|
appUrl: trimTrailingSlash(
|
|
238
|
-
nonEmpty(
|
|
239
|
-
nonEmpty(process.env.FREESTYLE_STACK_APP_URL) ??
|
|
247
|
+
nonEmpty(process.env.FREESTYLE_STACK_APP_URL) ??
|
|
240
248
|
dashboardUrl,
|
|
241
249
|
),
|
|
242
250
|
dashboardUrl,
|
|
243
251
|
projectId:
|
|
244
|
-
nonEmpty(
|
|
245
|
-
nonEmpty(process.env.FREESTYLE_STACK_PROJECT_ID) ??
|
|
252
|
+
nonEmpty(process.env.FREESTYLE_STACK_PROJECT_ID) ??
|
|
246
253
|
nonEmpty(process.env.NEXT_PUBLIC_STACK_PROJECT_ID) ??
|
|
247
254
|
nonEmpty(process.env.VITE_STACK_PROJECT_ID) ??
|
|
248
255
|
DEFAULT_STACK_PROJECT_ID,
|
|
249
256
|
publishableClientKey:
|
|
250
|
-
nonEmpty(
|
|
251
|
-
nonEmpty(process.env.FREESTYLE_STACK_PUBLISHABLE_CLIENT_KEY) ??
|
|
257
|
+
nonEmpty(process.env.FREESTYLE_STACK_PUBLISHABLE_CLIENT_KEY) ??
|
|
252
258
|
nonEmpty(process.env.NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY) ??
|
|
253
259
|
nonEmpty(process.env.VITE_STACK_PUBLISHABLE_CLIENT_KEY) ??
|
|
254
260
|
DEFAULT_STACK_PUBLISHABLE_CLIENT_KEY,
|
|
@@ -256,6 +262,13 @@ function resolveStackAuthConfig(auth: FreestyleProviderAuthConfig | undefined):
|
|
|
256
262
|
};
|
|
257
263
|
}
|
|
258
264
|
|
|
265
|
+
function withRigkitHeaders(headers: HeadersInit | undefined): Headers {
|
|
266
|
+
const next = new Headers(headers);
|
|
267
|
+
next.set(RIGKIT_HEADER, "true");
|
|
268
|
+
next.set(RIGKIT_VERSION_HEADER, RIGKIT_PROVIDER_FREESTYLE_VERSION);
|
|
269
|
+
return next;
|
|
270
|
+
}
|
|
271
|
+
|
|
259
272
|
async function resolveStackAccessToken(input: {
|
|
260
273
|
config: StackAuthConfig;
|
|
261
274
|
storage: ProviderStorage;
|
|
@@ -432,7 +445,7 @@ async function resolveTeamId(input: {
|
|
|
432
445
|
|
|
433
446
|
const choices = teams.map((team) => `${team.displayName ?? team.id} (${team.id})`).join(", ");
|
|
434
447
|
throw new Error(
|
|
435
|
-
`Freestyle authentication found multiple teams. Set freestyle.provider({
|
|
448
|
+
`Freestyle authentication found multiple teams. Set freestyle.provider({ teamId }) or FREESTYLE_TEAM_ID. Teams: ${choices}`,
|
|
436
449
|
);
|
|
437
450
|
}
|
|
438
451
|
|
|
@@ -515,14 +528,14 @@ function normalizeProxyError(errorText: string, status: number): { body: string;
|
|
|
515
528
|
try {
|
|
516
529
|
const parsed = JSON.parse(errorText) as Record<string, unknown>;
|
|
517
530
|
if (typeof parsed.code === "string" && typeof parsed.message === "string") {
|
|
518
|
-
return { body: JSON.stringify(parsed), contentType: "application/json" };
|
|
531
|
+
return { body: JSON.stringify(redactProxyErrorDetails(parsed)), contentType: "application/json" };
|
|
519
532
|
}
|
|
520
533
|
const message = [parsed.error, parsed.message, parsed.reason].find((value) =>
|
|
521
534
|
typeof value === "string" && value.length > 0
|
|
522
535
|
);
|
|
523
536
|
if (typeof message === "string") {
|
|
524
537
|
return {
|
|
525
|
-
body: JSON.stringify({ code: fallbackCode, message }),
|
|
538
|
+
body: JSON.stringify({ code: fallbackCode, message, details: redactProxyErrorDetails(parsed) }),
|
|
526
539
|
contentType: "application/json",
|
|
527
540
|
};
|
|
528
541
|
}
|
|
@@ -535,6 +548,17 @@ function normalizeProxyError(errorText: string, status: number): { body: string;
|
|
|
535
548
|
};
|
|
536
549
|
}
|
|
537
550
|
|
|
551
|
+
function redactProxyErrorDetails(value: Record<string, unknown>): Record<string, unknown> {
|
|
552
|
+
const details: Record<string, unknown> = {};
|
|
553
|
+
for (const [key, field] of Object.entries(value)) {
|
|
554
|
+
details[key] = /authorization|api[-_]?key|access[-_]?token|refresh[-_]?token|password|secret|credential|cookie/i
|
|
555
|
+
.test(key)
|
|
556
|
+
? "[redacted]"
|
|
557
|
+
: field;
|
|
558
|
+
}
|
|
559
|
+
return details;
|
|
560
|
+
}
|
|
561
|
+
|
|
538
562
|
function isBackgroundRequestPending(value: unknown): boolean {
|
|
539
563
|
return Boolean(
|
|
540
564
|
isRecord(value) &&
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { freestyleIdentityId, freestyleToken, freestyleTokenId } from "./auth.ts
|
|
|
8
8
|
import {
|
|
9
9
|
createFreestyleAuthenticatedClient,
|
|
10
10
|
createFreestyleProxyFetch,
|
|
11
|
-
type
|
|
11
|
+
type FreestyleProviderConfig,
|
|
12
12
|
} from "./host-auth.ts";
|
|
13
13
|
import {
|
|
14
14
|
FREESTYLE_PROVIDER_ID,
|
|
@@ -18,22 +18,15 @@ import {
|
|
|
18
18
|
} from "./provider.ts";
|
|
19
19
|
import type { FreestyleRuntime, FreestyleTerminalRuntime } from "./provider.ts";
|
|
20
20
|
|
|
21
|
-
const freestyleProviderConfigSchema = z.
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
dashboardUrl: z.optional(z.string().check(z.minLength(1))),
|
|
28
|
-
stackApiUrl: z.optional(z.string().check(z.minLength(1))),
|
|
29
|
-
stackAppUrl: z.optional(z.string().check(z.minLength(1))),
|
|
30
|
-
stackProjectId: z.optional(z.string().check(z.minLength(1))),
|
|
31
|
-
stackPublishableClientKey: z.optional(z.string().check(z.minLength(1))),
|
|
32
|
-
})),
|
|
21
|
+
const freestyleProviderConfigSchema = z.strictObject({
|
|
22
|
+
apiKey: z.optional(z.string().check(z.minLength(1))),
|
|
23
|
+
profile: z.optional(z.string().check(z.minLength(1))),
|
|
24
|
+
teamId: z.optional(z.string().check(z.minLength(1))),
|
|
25
|
+
apiUrl: z.optional(z.string().check(z.minLength(1))),
|
|
26
|
+
dashboardUrl: z.optional(z.string().check(z.minLength(1))),
|
|
33
27
|
});
|
|
34
28
|
|
|
35
|
-
export type FreestyleProviderConfig
|
|
36
|
-
export type { FreestyleProviderAuthConfig };
|
|
29
|
+
export type { FreestyleProviderConfig };
|
|
37
30
|
|
|
38
31
|
export type FreestyleProviderDefinition = WorkflowProviderDefinition<
|
|
39
32
|
typeof FREESTYLE_PROVIDER_ID,
|
|
@@ -41,6 +34,10 @@ export type FreestyleProviderDefinition = WorkflowProviderDefinition<
|
|
|
41
34
|
FreestyleRuntime
|
|
42
35
|
>;
|
|
43
36
|
|
|
37
|
+
export type FreestyleProviderOptions =
|
|
38
|
+
| string
|
|
39
|
+
| FreestyleProviderDefinition["config"];
|
|
40
|
+
|
|
44
41
|
export type FreestyleTerminalProviderDefinition = WorkflowProviderDefinition<
|
|
45
42
|
typeof FREESTYLE_TERMINAL_PROVIDER_ID,
|
|
46
43
|
{},
|
|
@@ -48,9 +45,9 @@ export type FreestyleTerminalProviderDefinition = WorkflowProviderDefinition<
|
|
|
48
45
|
>;
|
|
49
46
|
|
|
50
47
|
export function provider(
|
|
51
|
-
config:
|
|
48
|
+
config: FreestyleProviderOptions = {},
|
|
52
49
|
): FreestyleProviderDefinition {
|
|
53
|
-
return defineProvider(FREESTYLE_PROVIDER_ID, config, freestyleProviderPlugin);
|
|
50
|
+
return defineProvider(FREESTYLE_PROVIDER_ID, normalizeFreestyleProviderOptions(config), freestyleProviderPlugin);
|
|
54
51
|
}
|
|
55
52
|
|
|
56
53
|
export function terminal(): FreestyleTerminalProviderDefinition {
|
|
@@ -69,7 +66,7 @@ export const freestyleProviderPlugin: BaseProviderPlugin = {
|
|
|
69
66
|
async createProvider({ provider, hostStorage, local }) {
|
|
70
67
|
const config = parseFreestyleProviderConfig(provider.config);
|
|
71
68
|
const authenticated = await createFreestyleAuthenticatedClient({
|
|
72
|
-
|
|
69
|
+
config,
|
|
73
70
|
hostStorage,
|
|
74
71
|
local,
|
|
75
72
|
});
|
|
@@ -91,6 +88,7 @@ export const freestyleTerminalPlugin: BaseProviderPlugin = {
|
|
|
91
88
|
export {
|
|
92
89
|
createFreestyleAuthenticatedClient,
|
|
93
90
|
createFreestyleProxyFetch,
|
|
91
|
+
createFreestyleSdkFetch,
|
|
94
92
|
} from "./host-auth.ts";
|
|
95
93
|
export {
|
|
96
94
|
freestyleIdentityId,
|
|
@@ -124,9 +122,16 @@ export type {
|
|
|
124
122
|
export type { FreestyleGitRelationship, FreestyleIdentity } from "./store.ts";
|
|
125
123
|
|
|
126
124
|
function parseFreestyleProviderConfig(value: unknown): FreestyleProviderConfig {
|
|
127
|
-
const result = z.safeParse(freestyleProviderConfigSchema, value);
|
|
125
|
+
const result = z.safeParse(freestyleProviderConfigSchema, normalizeFreestyleProviderOptions(value));
|
|
128
126
|
if (!result.success) {
|
|
129
127
|
throw new Error(`Invalid Freestyle provider config:\n${z.prettifyError(result.error)}`);
|
|
130
128
|
}
|
|
131
129
|
return result.data;
|
|
132
130
|
}
|
|
131
|
+
|
|
132
|
+
function normalizeFreestyleProviderOptions(value: unknown): FreestyleProviderDefinition["config"] {
|
|
133
|
+
if (typeof value === "string") {
|
|
134
|
+
return { apiKey: value };
|
|
135
|
+
}
|
|
136
|
+
return value as FreestyleProviderDefinition["config"];
|
|
137
|
+
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const RIGKIT_PROVIDER_FREESTYLE_VERSION = "0.2.
|
|
1
|
+
export const RIGKIT_PROVIDER_FREESTYLE_VERSION = "0.2.9";
|