orizu 0.5.50 → 0.5.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app-commands.d.ts.map +1 -1
- package/dist/app-commands.js +4 -12
- package/dist/auth-commands.d.ts.map +1 -1
- package/dist/auth-commands.js +13 -112
- package/dist/cli-write-commands.d.ts +143 -0
- package/dist/cli-write-commands.d.ts.map +1 -0
- package/dist/cli-write-commands.js +123 -0
- package/dist/credentials-transaction.d.ts +7 -0
- package/dist/credentials-transaction.d.ts.map +1 -0
- package/dist/credentials-transaction.js +60 -0
- package/dist/credentials.d.ts +19 -1
- package/dist/credentials.d.ts.map +1 -1
- package/dist/credentials.js +118 -73
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -50
- package/dist/last-error-record.d.ts +7 -0
- package/dist/last-error-record.d.ts.map +1 -1
- package/dist/last-error-record.js +14 -2
- package/dist/login-flow.d.ts +37 -0
- package/dist/login-flow.d.ts.map +1 -0
- package/dist/login-flow.js +295 -0
- package/dist/logout-diagnostic.d.ts.map +1 -1
- package/dist/logout-diagnostic.js +2 -1
- package/dist/manifests-cli.d.ts.map +1 -1
- package/dist/manifests-cli.js +36 -22
- package/dist/one-request-write.d.ts +59 -0
- package/dist/one-request-write.d.ts.map +1 -0
- package/dist/one-request-write.js +157 -0
- package/dist/provider-write-workflow.d.ts +12 -0
- package/dist/provider-write-workflow.d.ts.map +1 -0
- package/dist/provider-write-workflow.js +110 -0
- package/dist/providers-cli.d.ts.map +1 -1
- package/dist/providers-cli.js +27 -23
- package/dist/scores-accept-cli.d.ts +1 -1
- package/dist/scores-accept-cli.d.ts.map +1 -1
- package/dist/scores-accept-cli.js +4 -28
- package/dist/stored-session-requests.d.ts.map +1 -1
- package/dist/stored-session-requests.js +8 -4
- package/dist/task-commands.d.ts.map +1 -1
- package/dist/task-commands.js +26 -62
- package/package.json +1 -1
- package/src/app-commands.ts +3 -18
- package/src/auth-commands.ts +17 -131
- package/src/cli-write-commands.ts +143 -0
- package/src/credentials-transaction.ts +73 -0
- package/src/credentials.ts +128 -86
- package/src/index.ts +23 -57
- package/src/last-error-record.ts +16 -2
- package/src/login-flow.ts +368 -0
- package/src/logout-diagnostic.ts +2 -1
- package/src/manifests-cli.ts +36 -23
- package/src/one-request-write.ts +192 -0
- package/src/provider-write-workflow.ts +117 -0
- package/src/providers-cli.ts +24 -17
- package/src/scores-accept-cli.ts +4 -46
- package/src/stored-session-requests.ts +7 -4
- package/src/task-commands.ts +22 -115
- package/dist/headless-login.d.ts +0 -19
- package/dist/headless-login.d.ts.map +0 -1
- package/dist/headless-login.js +0 -108
- package/src/headless-login.ts +0 -192
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-commands.d.ts","sourceRoot":"","sources":["../src/app-commands.ts"],"names":[],"mappings":"AAuCA,iBAAe,QAAQ,kBActB;AAED,iBAAS,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAU/C;AAED,iBAAS,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAUhD;AAED,iBAAS,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE9D;AAeD,iBAAS,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAElE;AAED,iBAAS,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG1F;AAED,iBAAS,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUjE;AAED,iBAAS,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAEjD;AAED,iBAAS,qBAAqB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG;IACpF,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;CACb,CAeA;AAED,iBAAS,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM;;;;;IAoB/E;AAED,iBAAS,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,QAGjE;AAED,iBAAS,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEjE;AAyED,iBAAe,iBAAiB,kBAmG/B;AAED,iBAAe,kBAAkB,kBAiDhC;AAED,iBAAe,iBAAiB,kBAwF/B;AAED,iBAAe,cAAc,
|
|
1
|
+
{"version":3,"file":"app-commands.d.ts","sourceRoot":"","sources":["../src/app-commands.ts"],"names":[],"mappings":"AAuCA,iBAAe,QAAQ,kBActB;AAED,iBAAS,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAU/C;AAED,iBAAS,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAUhD;AAED,iBAAS,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE9D;AAeD,iBAAS,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAElE;AAED,iBAAS,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG1F;AAED,iBAAS,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUjE;AAED,iBAAS,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAEjD;AAED,iBAAS,qBAAqB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG;IACpF,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;CACb,CAeA;AAED,iBAAS,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM;;;;;IAoB/E;AAED,iBAAS,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,QAGjE;AAED,iBAAS,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEjE;AAyED,iBAAe,iBAAiB,kBAmG/B;AAED,iBAAe,kBAAkB,kBAiDhC;AAED,iBAAe,iBAAiB,kBAwF/B;AAED,iBAAe,cAAc,kBAiC5B;AA+CD,iBAAe,SAAS,kBA2CvB;AAED,yFAAyF;AACzF,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAK3G;AAED,iBAAe,eAAe,kBAmD7B;AAED,OAAO,EACL,cAAc,EACd,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACR,gBAAgB,EAChB,wBAAwB,EACxB,SAAS,EACT,eAAe,EACf,QAAQ,EACR,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,SAAS,EACT,eAAe,GAChB,CAAA"}
|
package/dist/app-commands.js
CHANGED
|
@@ -433,18 +433,10 @@ async function linkAppDataset() {
|
|
|
433
433
|
const selected = await selectAppIdInteractively(project);
|
|
434
434
|
appId = selected.appId;
|
|
435
435
|
}
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
datasetId,
|
|
441
|
-
versionNum,
|
|
442
|
-
}),
|
|
443
|
-
});
|
|
444
|
-
if (!response.ok) {
|
|
445
|
-
throw new Error(`Failed to link dataset: ${await response.text()}`);
|
|
446
|
-
}
|
|
447
|
-
const data = await parseJsonResponse(response, 'App link dataset');
|
|
436
|
+
const writes = await import('./cli-write-commands.js');
|
|
437
|
+
const data = await writes.sendCommandWrite(writes.appLinkDataset(appId, { datasetId, ...(versionNum === undefined ? {} : { versionNum }) }), { json: hasJsonFlag(), print: printLine });
|
|
438
|
+
if (!data)
|
|
439
|
+
return;
|
|
448
440
|
if (hasJsonFlag()) {
|
|
449
441
|
printJson({ app: data.app, linkedDataset: data.linkedDataset, versionNum: data.versionNum });
|
|
450
442
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-commands.d.ts","sourceRoot":"","sources":["../src/auth-commands.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auth-commands.d.ts","sourceRoot":"","sources":["../src/auth-commands.ts"],"names":[],"mappings":"AAyBA,iBAAS,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,cAAc,CAEnE;AAMD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAQD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,GAAG,CAwB5E;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAgBtD;AAED,iBAAS,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzC;AA4BD,iBAAe,KAAK,CAAC,eAAe,CAAC,EAAE,MAAM,iBAoC5C;AA4BD,iBAAe,MAAM,kBAWpB;AAED,iBAAe,MAAM,CAAC,eAAe,CAAC,EAAE,MAAM,iBAwC7C;AAED,iBAAe,QAAQ,kBA0BtB;AAED,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAA"}
|
package/dist/auth-commands.js
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
// ORI-2044: moved from index.ts to keep auth commands together.
|
|
2
2
|
import { randomBytes, createHash } from 'crypto';
|
|
3
|
-
import { spawn } from 'child_process';
|
|
4
|
-
import { createServer } from 'http';
|
|
5
3
|
import { sanitizeTerminalText, parseJsonResponse } from './json-response.js';
|
|
6
4
|
import { isInteractiveTerminal, hasArg, hasJsonFlag, getArg } from './command-line-arguments.js';
|
|
7
5
|
import { getBaseUrl, resolveLoginTarget, resolveLogoutTarget, assertSecureTokenTransport, authedFetch, } from './http.js';
|
|
8
6
|
import { clearUnreadableServerCredentials, hasResolvableAuth, rememberProcessSecret, saveServerCredentials, getServerCredentials, resolveAuthTokenForBaseUrl, } from './credentials.js';
|
|
9
7
|
import { printJson, printLine, printLoginProgress } from './cli-console-output.js';
|
|
10
|
-
import { shouldUseHeadlessLogin, waitForHeadlessAuthorization } from './headless-login.js';
|
|
11
|
-
import { renderCliAuthBrowserPage } from './cli-auth-browser-page.js';
|
|
12
8
|
import { resolveProjectSelection } from './account-directory.js';
|
|
13
9
|
function isNodeError(error) {
|
|
14
10
|
return error instanceof Error;
|
|
@@ -46,30 +42,6 @@ export function validateBrowserUrl(url, expectedOrigin) {
|
|
|
46
42
|
}
|
|
47
43
|
return parsed;
|
|
48
44
|
}
|
|
49
|
-
function openInBrowser(url) {
|
|
50
|
-
const parsed = validateBrowserUrl(url);
|
|
51
|
-
const platform = process.platform;
|
|
52
|
-
const href = parsed.href;
|
|
53
|
-
if (platform === 'darwin') {
|
|
54
|
-
spawn('open', [href], {
|
|
55
|
-
detached: true,
|
|
56
|
-
stdio: 'ignore',
|
|
57
|
-
}).unref();
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
if (platform === 'win32') {
|
|
61
|
-
spawn('rundll32.exe', ['url.dll,FileProtocolHandler', href], {
|
|
62
|
-
detached: true,
|
|
63
|
-
stdio: 'ignore',
|
|
64
|
-
windowsHide: true,
|
|
65
|
-
}).unref();
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
spawn('xdg-open', [href], {
|
|
69
|
-
detached: true,
|
|
70
|
-
stdio: 'ignore',
|
|
71
|
-
}).unref();
|
|
72
|
-
}
|
|
73
45
|
export function formatTerminalLink(url) {
|
|
74
46
|
const safeUrl = sanitizeTerminalText(url);
|
|
75
47
|
try {
|
|
@@ -101,6 +73,9 @@ function resolveAuthCallbackPort() {
|
|
|
101
73
|
}
|
|
102
74
|
return parsed;
|
|
103
75
|
}
|
|
76
|
+
function isCredentialsFileFailure(message) {
|
|
77
|
+
return message.startsWith('ORIZU_CREDENTIALS_READ_FAILED:') || message.startsWith('ORIZU_CREDENTIALS_WRITE_FAILED:');
|
|
78
|
+
}
|
|
104
79
|
async function login(baseUrlOverride) {
|
|
105
80
|
const target = baseUrlOverride !== undefined
|
|
106
81
|
? { baseUrl: baseUrlOverride, isDefault: false }
|
|
@@ -113,14 +88,15 @@ async function login(baseUrlOverride) {
|
|
|
113
88
|
loginData = await authenticateAtBaseUrl(baseUrl);
|
|
114
89
|
if (!loginData)
|
|
115
90
|
return;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
});
|
|
91
|
+
const apiKey = loginData.apiKey;
|
|
92
|
+
// Waits for the lock without freezing the CLI (ORI-2421).
|
|
93
|
+
const { withCredentialsTransaction } = await import('./credentials-transaction.js');
|
|
94
|
+
await withCredentialsTransaction(async () => saveServerCredentials(baseUrl, { credentialType: 'pat', apiKey }));
|
|
120
95
|
}
|
|
121
96
|
catch (error) {
|
|
122
|
-
|
|
123
|
-
|
|
97
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
98
|
+
// Reading or saving credentials.json is a disk problem, not a connection one.
|
|
99
|
+
if (target.isDefault && !isCredentialsFileFailure(detail)) {
|
|
124
100
|
throw new Error(`${detail} Check connectivity to https://app.orizu.ai, then retry \`orizu login\`.`, { cause: error });
|
|
125
101
|
}
|
|
126
102
|
throw error;
|
|
@@ -150,85 +126,10 @@ async function authenticateAtBaseUrl(baseUrl) {
|
|
|
150
126
|
}
|
|
151
127
|
const codeVerifier = rememberProcessSecret(createCodeVerifier());
|
|
152
128
|
const codeChallenge = createCodeChallenge(codeVerifier);
|
|
129
|
+
// Effect loads here, after the already-logged-in check (ORI-2422).
|
|
130
|
+
const { completeLogin, shouldUseHeadlessLogin } = await import('./login-flow.js');
|
|
153
131
|
const isHeadlessLogin = shouldUseHeadlessLogin({ isForced: hasArg('--headless') });
|
|
154
|
-
|
|
155
|
-
const redirectUri = callbackPort === undefined ? undefined : `http://127.0.0.1:${callbackPort}/callback`;
|
|
156
|
-
const callbackCode = isHeadlessLogin
|
|
157
|
-
? await waitForHeadlessAuthorization({ baseUrl, codeChallenge }, {
|
|
158
|
-
parseJsonResponse,
|
|
159
|
-
printProgress: printLoginProgress,
|
|
160
|
-
sanitizeTerminalText,
|
|
161
|
-
validateBrowserUrl,
|
|
162
|
-
})
|
|
163
|
-
: await new Promise((resolve, reject) => {
|
|
164
|
-
const server = createServer((request, response) => {
|
|
165
|
-
try {
|
|
166
|
-
const url = new URL(request.url || '/', `http://127.0.0.1:${callbackPort}`);
|
|
167
|
-
const code = url.searchParams.get('code');
|
|
168
|
-
if (!code) {
|
|
169
|
-
response.statusCode = 400;
|
|
170
|
-
response.setHeader('content-type', 'text/html; charset=utf-8');
|
|
171
|
-
response.end(renderCliAuthBrowserPage('error'));
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
response.statusCode = 200;
|
|
175
|
-
response.setHeader('content-type', 'text/html; charset=utf-8');
|
|
176
|
-
response.end(renderCliAuthBrowserPage('success'));
|
|
177
|
-
server.close();
|
|
178
|
-
resolve(code);
|
|
179
|
-
}
|
|
180
|
-
catch (error) {
|
|
181
|
-
server.close();
|
|
182
|
-
reject(error);
|
|
183
|
-
}
|
|
184
|
-
});
|
|
185
|
-
server.on('error', (error) => {
|
|
186
|
-
if (error.code === 'EADDRINUSE') {
|
|
187
|
-
reject(new Error(`Port ${callbackPort} is already in use. Set ORIZU_AUTH_PORT to a different port (1024–65535) and retry.`));
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
reject(error);
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
server.listen(callbackPort, '127.0.0.1', async () => {
|
|
194
|
-
try {
|
|
195
|
-
const response = await fetch(`${baseUrl}/api/cli/auth/start`, {
|
|
196
|
-
method: 'POST',
|
|
197
|
-
headers: { 'Content-Type': 'application/json' },
|
|
198
|
-
body: JSON.stringify({ codeChallenge, redirectUri }),
|
|
199
|
-
});
|
|
200
|
-
if (!response.ok) {
|
|
201
|
-
const text = await response.text();
|
|
202
|
-
server.close();
|
|
203
|
-
reject(new Error(`Failed to start login: ${text}`));
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
const { authorizeUrl } = await parseJsonResponse(response, 'CLI auth start');
|
|
207
|
-
const safeAuthorizeUrl = validateBrowserUrl(authorizeUrl, baseUrl).href;
|
|
208
|
-
printLoginProgress(`Opening browser for login: ${sanitizeTerminalText(safeAuthorizeUrl)}`);
|
|
209
|
-
openInBrowser(safeAuthorizeUrl);
|
|
210
|
-
}
|
|
211
|
-
catch (error) {
|
|
212
|
-
server.close();
|
|
213
|
-
reject(error);
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
rememberProcessSecret(callbackCode);
|
|
218
|
-
const exchangeResponse = await fetch(`${baseUrl}/api/cli/auth/exchange`, {
|
|
219
|
-
method: 'POST',
|
|
220
|
-
headers: { 'Content-Type': 'application/json' },
|
|
221
|
-
body: JSON.stringify({ code: callbackCode, codeVerifier, redirectUri }),
|
|
222
|
-
});
|
|
223
|
-
if (!exchangeResponse.ok) {
|
|
224
|
-
const text = await exchangeResponse.text();
|
|
225
|
-
throw new Error(`Failed to exchange auth code: ${text}`);
|
|
226
|
-
}
|
|
227
|
-
const loginData = await parseJsonResponse(exchangeResponse, 'CLI auth exchange');
|
|
228
|
-
if (!loginData.apiKey) {
|
|
229
|
-
throw new Error('Server did not return an API key. Upgrade the Orizu server and run `orizu login` again.');
|
|
230
|
-
}
|
|
231
|
-
return { ...loginData, apiKey: loginData.apiKey };
|
|
132
|
+
return completeLogin({ baseUrl, codeVerifier, codeChallenge, callbackPort: isHeadlessLogin ? undefined : resolveAuthCallbackPort() }, { parseJsonResponse, printProgress: printLoginProgress, sanitizeTerminalText, validateBrowserUrl });
|
|
232
133
|
}
|
|
233
134
|
async function whoami() {
|
|
234
135
|
const response = await authedFetch('/api/cli/auth/whoami');
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { Schema } from 'effect';
|
|
2
|
+
import { type OneRequestWrite } from './one-request-write.js';
|
|
3
|
+
type Write<A> = Pick<OneRequestWrite<A>, 'label' | 'name' | 'path' | 'method' | 'body' | 'reply' | 'mayAlreadyBeSaved' | 'describeError'>;
|
|
4
|
+
declare const TaskCreated: Schema.Struct<{
|
|
5
|
+
readonly task: Schema.Struct<{
|
|
6
|
+
readonly id: Schema.String;
|
|
7
|
+
readonly title: Schema.String;
|
|
8
|
+
readonly status: Schema.String;
|
|
9
|
+
readonly requiredAssignmentsPerRow: Schema.Number;
|
|
10
|
+
readonly versionId: Schema.String;
|
|
11
|
+
readonly versionNum: Schema.Number;
|
|
12
|
+
}>;
|
|
13
|
+
readonly assignmentsCreated: Schema.Number;
|
|
14
|
+
readonly assignmentShortfall: Schema.optionalKey<Schema.Number>;
|
|
15
|
+
readonly warning: Schema.optionalKey<Schema.String>;
|
|
16
|
+
}>;
|
|
17
|
+
/** Running it again makes a second task (and, with --publish, emails labellers again). */
|
|
18
|
+
export declare const taskCreate: (body: Record<string, unknown>, describeError: Write<typeof TaskCreated.Type>["describeError"]) => Write<typeof TaskCreated.Type>;
|
|
19
|
+
declare const TaskUpdated: Schema.Struct<{
|
|
20
|
+
readonly task: Schema.Struct<{
|
|
21
|
+
readonly id: Schema.String;
|
|
22
|
+
readonly title: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
23
|
+
readonly status: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
24
|
+
readonly dataset_id: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
25
|
+
readonly app_id: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
26
|
+
readonly version_id: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
27
|
+
readonly required_assignments_per_row: Schema.optionalKey<Schema.NullOr<Schema.Number>>;
|
|
28
|
+
}>;
|
|
29
|
+
readonly assignmentMode: Schema.optionalKey<Schema.String>;
|
|
30
|
+
readonly assignmentsCreated: Schema.optionalKey<Schema.Number>;
|
|
31
|
+
}>;
|
|
32
|
+
/** Sets the same values again, so a repeat is safe. */
|
|
33
|
+
export declare const taskUpdate: (id: string, body: Record<string, unknown>) => Write<typeof TaskUpdated.Type>;
|
|
34
|
+
declare const Discarded: Schema.Struct<{
|
|
35
|
+
readonly success: Schema.Boolean;
|
|
36
|
+
}>;
|
|
37
|
+
/** Once the draft is gone, a repeat is refused as "not found". */
|
|
38
|
+
export declare const taskDiscard: (id: string) => Write<typeof Discarded.Type>;
|
|
39
|
+
declare const Published: Schema.Struct<{
|
|
40
|
+
readonly assignmentsProcessed: Schema.Number;
|
|
41
|
+
readonly assignmentsCreated: Schema.Number;
|
|
42
|
+
readonly assignmentsRemoved: Schema.optionalKey<Schema.Number>;
|
|
43
|
+
readonly assignmentShortfall: Schema.optionalKey<Schema.Number>;
|
|
44
|
+
readonly warning: Schema.optionalKey<Schema.String>;
|
|
45
|
+
readonly task: Schema.Struct<{
|
|
46
|
+
readonly id: Schema.String;
|
|
47
|
+
readonly status: Schema.String;
|
|
48
|
+
}>;
|
|
49
|
+
}>;
|
|
50
|
+
/** Once published, a repeat is refused as "must be a draft". */
|
|
51
|
+
export declare const taskPublish: (id: string, body: Record<string, unknown>) => Write<typeof Published.Type>;
|
|
52
|
+
declare const Assigned: Schema.Struct<{
|
|
53
|
+
assignmentsCreated: Schema.Number;
|
|
54
|
+
assignmentsProcessed: Schema.optionalKey<Schema.Number>;
|
|
55
|
+
assignmentsRemoved: Schema.optionalKey<Schema.Number>;
|
|
56
|
+
assignmentShortfall: Schema.optionalKey<Schema.Number>;
|
|
57
|
+
warning: Schema.optionalKey<Schema.String>;
|
|
58
|
+
}>;
|
|
59
|
+
/** Adds only missing pairs and emails only new people, so a repeat is safe. */
|
|
60
|
+
export declare const taskAssign: (id: string, body: Record<string, unknown>) => Write<typeof Assigned.Type>;
|
|
61
|
+
declare const StatusChanged: Schema.Struct<{
|
|
62
|
+
readonly task: Schema.Struct<{
|
|
63
|
+
readonly id: Schema.String;
|
|
64
|
+
readonly status: Schema.String;
|
|
65
|
+
}>;
|
|
66
|
+
}>;
|
|
67
|
+
/** Setting the status a task already has changes nothing. */
|
|
68
|
+
export declare const taskStatus: (id: string, verb: string, status: string) => Write<typeof StatusChanged.Type>;
|
|
69
|
+
declare const RunStarted: Schema.Struct<{
|
|
70
|
+
readonly optimization_run_id: Schema.String;
|
|
71
|
+
readonly optimizationRun: Schema.Struct<{
|
|
72
|
+
readonly id: Schema.String;
|
|
73
|
+
readonly status: Schema.String;
|
|
74
|
+
readonly startedAt: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
75
|
+
readonly createdAt: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
76
|
+
}>;
|
|
77
|
+
}>;
|
|
78
|
+
/** The server picks a new run id per request, so running it again starts a second run. */
|
|
79
|
+
export declare const optimizationStart: (project: string, body: Record<string, unknown>) => Write<typeof RunStarted.Type>;
|
|
80
|
+
declare const RunChanged: Schema.Struct<{
|
|
81
|
+
readonly optimizationRun: Schema.Struct<{
|
|
82
|
+
readonly id: Schema.String;
|
|
83
|
+
readonly status: Schema.optionalKey<Schema.String>;
|
|
84
|
+
readonly startedAt: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
85
|
+
readonly finishedAt: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
86
|
+
readonly bestScore: Schema.optionalKey<Schema.NullOr<Schema.Number>>;
|
|
87
|
+
readonly bestCandidateId: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
88
|
+
readonly resultPromptVersionId: Schema.optionalKey<Schema.NullOr<Schema.String>>;
|
|
89
|
+
readonly metadata: Schema.optionalKey<Schema.$Record<Schema.String, Schema.Unknown>>;
|
|
90
|
+
}>;
|
|
91
|
+
readonly cancellationStatus: Schema.optionalKey<Schema.Literal<"already_terminal">>;
|
|
92
|
+
}>;
|
|
93
|
+
/** Writing the status a run already has again converges, so a repeat is safe. */
|
|
94
|
+
export declare const optimizationLifecycle: (runId: string, body: Record<string, unknown>) => Write<typeof RunChanged.Type>;
|
|
95
|
+
declare const EventLogged: Schema.Struct<{
|
|
96
|
+
readonly eventId: Schema.String;
|
|
97
|
+
}>;
|
|
98
|
+
/** A repeat with the same event id changes nothing; a new id is refused as a sequence clash. */
|
|
99
|
+
export declare const optimizationEvent: (runId: string, body: Record<string, unknown> & {
|
|
100
|
+
eventId: string;
|
|
101
|
+
}) => Write<typeof EventLogged.Type>;
|
|
102
|
+
declare const Linked: Schema.Struct<{
|
|
103
|
+
readonly app: Schema.Struct<{
|
|
104
|
+
readonly id: Schema.String;
|
|
105
|
+
readonly name: Schema.String;
|
|
106
|
+
}>;
|
|
107
|
+
readonly linkedDataset: Schema.Struct<{
|
|
108
|
+
readonly id: Schema.String;
|
|
109
|
+
readonly name: Schema.String;
|
|
110
|
+
}>;
|
|
111
|
+
readonly versionNum: Schema.Number;
|
|
112
|
+
}>;
|
|
113
|
+
/**
|
|
114
|
+
* A plain overwrite, so a repeat is safe; without --version it links the
|
|
115
|
+
* app's current version at the time, which may have moved on.
|
|
116
|
+
*/
|
|
117
|
+
export declare const appLinkDataset: (appId: string, body: {
|
|
118
|
+
datasetId: string;
|
|
119
|
+
versionNum?: number;
|
|
120
|
+
}) => Write<typeof Linked.Type>;
|
|
121
|
+
declare const Accepted: Schema.Struct<{
|
|
122
|
+
readonly scoreRun: Schema.Struct<{
|
|
123
|
+
readonly id: Schema.String;
|
|
124
|
+
readonly provenance: Schema.String;
|
|
125
|
+
readonly acceptedByUserId: Schema.NullOr<Schema.String>;
|
|
126
|
+
readonly acceptedAt: Schema.NullOr<Schema.String>;
|
|
127
|
+
readonly alreadyAccepted: Schema.Boolean;
|
|
128
|
+
}>;
|
|
129
|
+
}>;
|
|
130
|
+
/** The first acceptance is kept and a repeat says "already accepted". */
|
|
131
|
+
export declare const scoreAccept: (project: string, scoreRunId: string) => Write<typeof Accepted.Type>;
|
|
132
|
+
declare const ManifestRejected: Schema.Struct<{
|
|
133
|
+
readonly manifest: Schema.$Record<Schema.String, Schema.Unknown>;
|
|
134
|
+
}>;
|
|
135
|
+
/** Once rejected, a repeat is refused, so the advice is to look first. */
|
|
136
|
+
export declare const manifestReject: (id: string) => Write<typeof ManifestRejected.Type>;
|
|
137
|
+
/** Sends a write with this command's `--json` setting and output. Ctrl-C sets the exit code and returns null. */
|
|
138
|
+
export declare function sendCommandWrite<A>(write: Write<A>, io: {
|
|
139
|
+
json: boolean;
|
|
140
|
+
print: (line: string) => void;
|
|
141
|
+
}): Promise<A | null>;
|
|
142
|
+
export {};
|
|
143
|
+
//# sourceMappingURL=cli-write-commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-write-commands.d.ts","sourceRoot":"","sources":["../src/cli-write-commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { Schema } from 'effect';
|
|
2
|
+
import { sendOneRequestWrite } from './one-request-write.js';
|
|
3
|
+
// ORI-2726: what each one-request write command sends, the reply it expects,
|
|
4
|
+
// and what to tell a person when the write may already be saved. The advice
|
|
5
|
+
// follows what the server does when the same request arrives twice. Loaded
|
|
6
|
+
// only through `await import(...)`, so commands that never write skip Effect.
|
|
7
|
+
const SAFE = 'running the same command again is safe';
|
|
8
|
+
const note = (thing, done, advice) => ({ thing, done, advice });
|
|
9
|
+
const task = (id) => `/api/cli/tasks/${encodeURIComponent(id)}`;
|
|
10
|
+
const Count = Schema.Number;
|
|
11
|
+
const Text = Schema.String;
|
|
12
|
+
const Assignments = {
|
|
13
|
+
assignmentsCreated: Count,
|
|
14
|
+
assignmentsProcessed: Schema.optionalKey(Count),
|
|
15
|
+
assignmentsRemoved: Schema.optionalKey(Count),
|
|
16
|
+
assignmentShortfall: Schema.optionalKey(Count),
|
|
17
|
+
warning: Schema.optionalKey(Text),
|
|
18
|
+
};
|
|
19
|
+
const TaskCreated = Schema.Struct({
|
|
20
|
+
task: Schema.Struct({ id: Text, title: Text, status: Text, requiredAssignmentsPerRow: Count, versionId: Text, versionNum: Count }),
|
|
21
|
+
assignmentsCreated: Count,
|
|
22
|
+
assignmentShortfall: Schema.optionalKey(Count),
|
|
23
|
+
warning: Schema.optionalKey(Text),
|
|
24
|
+
});
|
|
25
|
+
/** Running it again makes a second task (and, with --publish, emails labellers again). */
|
|
26
|
+
export const taskCreate = (body, describeError) => ({
|
|
27
|
+
label: 'create task', name: 'Task create', path: '/api/cli/tasks', method: 'POST', body, reply: TaskCreated, describeError,
|
|
28
|
+
mayAlreadyBeSaved: note('task', 'created', 'check `orizu tasks list` before creating it again (running it again makes a second task)'),
|
|
29
|
+
});
|
|
30
|
+
const Nullable = (schema) => Schema.optionalKey(Schema.NullOr(schema));
|
|
31
|
+
const TaskUpdated = Schema.Struct({
|
|
32
|
+
task: Schema.Struct({
|
|
33
|
+
id: Text, title: Nullable(Text), status: Nullable(Text), dataset_id: Nullable(Text), app_id: Nullable(Text),
|
|
34
|
+
version_id: Nullable(Text), required_assignments_per_row: Nullable(Count),
|
|
35
|
+
}),
|
|
36
|
+
assignmentMode: Schema.optionalKey(Text),
|
|
37
|
+
assignmentsCreated: Schema.optionalKey(Count),
|
|
38
|
+
});
|
|
39
|
+
/** Sets the same values again, so a repeat is safe. */
|
|
40
|
+
export const taskUpdate = (id, body) => ({
|
|
41
|
+
label: 'update task', name: 'Task update', path: task(id), method: 'PATCH', body, reply: TaskUpdated, mayAlreadyBeSaved: note('task change', 'saved', SAFE),
|
|
42
|
+
});
|
|
43
|
+
const Discarded = Schema.Struct({ success: Schema.Boolean });
|
|
44
|
+
/** Once the draft is gone, a repeat is refused as "not found". */
|
|
45
|
+
export const taskDiscard = (id) => ({
|
|
46
|
+
label: 'discard draft task', name: 'Draft discard', path: task(id), method: 'DELETE', reply: Discarded,
|
|
47
|
+
mayAlreadyBeSaved: note('draft', 'discarded', 'check `orizu tasks list`; once it is gone, running it again answers "Task not found or access denied"'),
|
|
48
|
+
});
|
|
49
|
+
const Published = Schema.Struct({ task: Schema.Struct({ id: Text, status: Text }), ...Assignments, assignmentsProcessed: Count });
|
|
50
|
+
/** Once published, a repeat is refused as "must be a draft". */
|
|
51
|
+
export const taskPublish = (id, body) => ({
|
|
52
|
+
label: 'publish task', name: 'Task publish', path: `${task(id)}/publish`, method: 'POST', body, reply: Published,
|
|
53
|
+
mayAlreadyBeSaved: note('task', 'published', `check \`orizu tasks status --task ${id}\`; once published, running it again answers "Task must be a draft before publishing"`),
|
|
54
|
+
});
|
|
55
|
+
const Assigned = Schema.Struct(Assignments);
|
|
56
|
+
/** Adds only missing pairs and emails only new people, so a repeat is safe. */
|
|
57
|
+
export const taskAssign = (id, body) => ({
|
|
58
|
+
label: 'assign task', name: 'Task assign', path: `${task(id)}/assign`, method: 'POST', body, reply: Assigned, mayAlreadyBeSaved: note('assignments', 'saved', SAFE),
|
|
59
|
+
});
|
|
60
|
+
const StatusChanged = Schema.Struct({ task: Schema.Struct({ id: Text, status: Text }) });
|
|
61
|
+
/** Setting the status a task already has changes nothing. */
|
|
62
|
+
export const taskStatus = (id, verb, status) => ({
|
|
63
|
+
label: `${verb} task`, name: `Task ${verb}`, path: `${task(id)}/status`, method: 'PATCH', body: { status }, reply: StatusChanged,
|
|
64
|
+
mayAlreadyBeSaved: note('task status change', 'saved', SAFE),
|
|
65
|
+
});
|
|
66
|
+
const RunStarted = Schema.Struct({
|
|
67
|
+
optimization_run_id: Text,
|
|
68
|
+
optimizationRun: Schema.Struct({ id: Text, status: Text, startedAt: Nullable(Text), createdAt: Nullable(Text) }),
|
|
69
|
+
});
|
|
70
|
+
/** The server picks a new run id per request, so running it again starts a second run. */
|
|
71
|
+
export const optimizationStart = (project, body) => ({
|
|
72
|
+
label: 'start optimization run', name: 'Optimization run start', path: `/api/cli/optimization-runs?project=${encodeURIComponent(project)}`, method: 'POST', body, reply: RunStarted,
|
|
73
|
+
mayAlreadyBeSaved: note('run', 'started', 'check `orizu optimizations list` before starting again (running it again starts a second run)'),
|
|
74
|
+
});
|
|
75
|
+
const RunChanged = Schema.Struct({
|
|
76
|
+
optimizationRun: Schema.Struct({
|
|
77
|
+
id: Text, status: Schema.optionalKey(Text), startedAt: Nullable(Text), finishedAt: Nullable(Text), bestScore: Nullable(Count),
|
|
78
|
+
bestCandidateId: Nullable(Text), resultPromptVersionId: Nullable(Text), metadata: Schema.optionalKey(Schema.Record(Text, Schema.Unknown)),
|
|
79
|
+
}),
|
|
80
|
+
cancellationStatus: Schema.optionalKey(Schema.Literal('already_terminal')),
|
|
81
|
+
});
|
|
82
|
+
/** Writing the status a run already has again converges, so a repeat is safe. */
|
|
83
|
+
export const optimizationLifecycle = (runId, body) => ({
|
|
84
|
+
label: 'update optimization run', name: 'Optimization run update', path: `/api/cli/optimization-runs/${encodeURIComponent(runId)}`, method: 'PATCH', body, reply: RunChanged,
|
|
85
|
+
mayAlreadyBeSaved: note('run status change', 'saved', SAFE),
|
|
86
|
+
});
|
|
87
|
+
const EventLogged = Schema.Struct({ eventId: Text });
|
|
88
|
+
/** A repeat with the same event id changes nothing; a new id is refused as a sequence clash. */
|
|
89
|
+
export const optimizationEvent = (runId, body) => ({
|
|
90
|
+
label: 'log event', name: 'Event log', path: `/api/cli/optimization-runs/${encodeURIComponent(runId)}/events`, method: 'POST', body, reply: EventLogged,
|
|
91
|
+
mayAlreadyBeSaved: note('event', 'logged', `run the same command again with \`--event-id ${body.eventId}\` (a new id would be refused as a clash)`),
|
|
92
|
+
});
|
|
93
|
+
const Linked = Schema.Struct({ app: Schema.Struct({ id: Text, name: Text }), linkedDataset: Schema.Struct({ id: Text, name: Text }), versionNum: Count });
|
|
94
|
+
/**
|
|
95
|
+
* A plain overwrite, so a repeat is safe; without --version it links the
|
|
96
|
+
* app's current version at the time, which may have moved on.
|
|
97
|
+
*/
|
|
98
|
+
export const appLinkDataset = (appId, body) => ({
|
|
99
|
+
label: 'link dataset', name: 'Dataset link', path: `/api/cli/apps/${encodeURIComponent(appId)}/link-dataset`, method: 'POST', body, reply: Linked,
|
|
100
|
+
mayAlreadyBeSaved: note('link', 'saved', body.versionNum === undefined ? 'running it again with `--version <n>` for the version you meant is safe' : SAFE),
|
|
101
|
+
});
|
|
102
|
+
const Accepted = Schema.Struct({
|
|
103
|
+
scoreRun: Schema.Struct({ id: Text, provenance: Text, acceptedByUserId: Schema.NullOr(Text), acceptedAt: Schema.NullOr(Text), alreadyAccepted: Schema.Boolean }),
|
|
104
|
+
});
|
|
105
|
+
/** The first acceptance is kept and a repeat says "already accepted". */
|
|
106
|
+
export const scoreAccept = (project, scoreRunId) => ({
|
|
107
|
+
label: 'accept score run', name: 'Score run accept', path: `/api/cli/scores/accept?project=${encodeURIComponent(project)}`, method: 'POST', body: { scoreRunId }, reply: Accepted,
|
|
108
|
+
mayAlreadyBeSaved: note('acceptance', 'saved', SAFE),
|
|
109
|
+
});
|
|
110
|
+
const ManifestRejected = Schema.Struct({ manifest: Schema.Record(Text, Schema.Unknown) });
|
|
111
|
+
/** Once rejected, a repeat is refused, so the advice is to look first. */
|
|
112
|
+
export const manifestReject = (id) => ({
|
|
113
|
+
label: 'reject manifest', name: 'Manifest reject', path: `/api/cli/promotion-manifests/${encodeURIComponent(id)}`, method: 'POST', body: { action: 'reject' }, reply: ManifestRejected,
|
|
114
|
+
mayAlreadyBeSaved: note('manifest', 'rejected', `check \`orizu manifests show ${id}\``),
|
|
115
|
+
});
|
|
116
|
+
/** Sends a write with this command's `--json` setting and output. Ctrl-C sets the exit code and returns null. */
|
|
117
|
+
export async function sendCommandWrite(write, io) {
|
|
118
|
+
const outcome = await sendOneRequestWrite({ ...write, ...io });
|
|
119
|
+
if (outcome.kind === 'saved')
|
|
120
|
+
return outcome.reply;
|
|
121
|
+
process.exitCode = outcome.exitCode;
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A credentials transaction whose wait for the lock stays responsive. The
|
|
3
|
+
* in-process rules are credentials.ts's: one holder per process, and nested
|
|
4
|
+
* writes only from the holder's own async context.
|
|
5
|
+
*/
|
|
6
|
+
export declare function withCredentialsTransaction<T>(operation: () => Promise<T>, signal?: AbortSignal | null): Promise<T>;
|
|
7
|
+
//# sourceMappingURL=credentials-transaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials-transaction.d.ts","sourceRoot":"","sources":["../src/credentials-transaction.ts"],"names":[],"mappings":"AA8DA;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,EAC1C,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI,GAC1B,OAAO,CAAC,CAAC,CAAC,CAEZ"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Waiting for the credentials lock without freezing the process (ORI-2421).
|
|
2
|
+
// Loaded only by stored-login code (refresh, logout, login), never on the
|
|
3
|
+
// ORIZU_TOKEN / ORIZU_TOKEN_FILE path, which must not load Effect.
|
|
4
|
+
import { Cause, Effect, Exit } from 'effect';
|
|
5
|
+
import { CREDENTIALS_LOCK_RETRY_MS, credentialsLockTimeoutError, credentialsLockTimeoutMs, releaseCredentialsLock, tryAcquireCredentialsLock, withCredentialsTransactionLockAsync, } from './credentials.js';
|
|
6
|
+
/**
|
|
7
|
+
* Try the lock, sleep, try again, until ORIZU_CREDENTIALS_LOCK_TIMEOUT_MS.
|
|
8
|
+
* Timers and stop handlers keep running while it waits, and `signal` stops
|
|
9
|
+
* the wait. A try is one synchronous step, so a stop never lands inside it.
|
|
10
|
+
* A lock a try takes is noted at once, and handed back if the run then ends
|
|
11
|
+
* any way other than returning it, wherever a stop lands.
|
|
12
|
+
*/
|
|
13
|
+
function acquireLock(signal) {
|
|
14
|
+
const timeoutMs = credentialsLockTimeoutMs();
|
|
15
|
+
const deadline = Date.now() + timeoutMs;
|
|
16
|
+
let taken = null;
|
|
17
|
+
const attempt = Effect.try({
|
|
18
|
+
try: () => (taken = tryAcquireCredentialsLock()),
|
|
19
|
+
catch: cause => cause instanceof Error ? cause : new Error(String(cause)),
|
|
20
|
+
});
|
|
21
|
+
const program = Effect.gen(function* () {
|
|
22
|
+
while (true) {
|
|
23
|
+
const lock = yield* attempt;
|
|
24
|
+
if (lock)
|
|
25
|
+
return lock;
|
|
26
|
+
const remainingMs = deadline - Date.now();
|
|
27
|
+
if (remainingMs <= 0)
|
|
28
|
+
return yield* Effect.fail(credentialsLockTimeoutError(timeoutMs));
|
|
29
|
+
yield* Effect.sleep(Math.min(CREDENTIALS_LOCK_RETRY_MS, remainingMs));
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
return run(program, signal, () => {
|
|
33
|
+
if (!taken)
|
|
34
|
+
return;
|
|
35
|
+
try {
|
|
36
|
+
releaseCredentialsLock(taken);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// The stop or failure is what the caller needs to see.
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/** A stop by `signal` rejects with its reason, as an aborted fetch would. */
|
|
44
|
+
async function run(program, signal, onNotReturned) {
|
|
45
|
+
const exit = await Effect.runPromiseExit(program, signal ? { signal } : undefined);
|
|
46
|
+
if (Exit.isSuccess(exit))
|
|
47
|
+
return exit.value;
|
|
48
|
+
onNotReturned();
|
|
49
|
+
if (signal?.aborted && Cause.hasInterruptsOnly(exit.cause))
|
|
50
|
+
throw signal.reason;
|
|
51
|
+
throw Cause.squash(exit.cause);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A credentials transaction whose wait for the lock stays responsive. The
|
|
55
|
+
* in-process rules are credentials.ts's: one holder per process, and nested
|
|
56
|
+
* writes only from the holder's own async context.
|
|
57
|
+
*/
|
|
58
|
+
export function withCredentialsTransaction(operation, signal) {
|
|
59
|
+
return withCredentialsTransactionLockAsync(operation, () => acquireLock(signal));
|
|
60
|
+
}
|
package/dist/credentials.d.ts
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
import { ServerCredentials, StoredCredentialsV2, StoredCredentialsV3 } from './types.js';
|
|
2
2
|
export declare function getConfigDir(): string;
|
|
3
|
+
export declare const CREDENTIALS_LOCK_RETRY_MS = 20;
|
|
4
|
+
export interface HeldCredentialsLock {
|
|
5
|
+
path: string;
|
|
6
|
+
metadata: string;
|
|
7
|
+
depth: number;
|
|
8
|
+
asyncOwner?: symbol;
|
|
9
|
+
released: Promise<void>;
|
|
10
|
+
resolveReleased: () => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function credentialsLockTimeoutMs(): number;
|
|
13
|
+
export declare function credentialsLockTimeoutError(timeoutMs: number): Error;
|
|
14
|
+
/**
|
|
15
|
+
* One try at the cross-process lock. Returns null when another owner holds
|
|
16
|
+
* it. The waits between tries belong to the caller: a blocking one below for
|
|
17
|
+
* synchronous writers, an Effect sleep in credentials-transaction.ts.
|
|
18
|
+
*/
|
|
19
|
+
export declare function tryAcquireCredentialsLock(): HeldCredentialsLock | null;
|
|
20
|
+
export declare function releaseCredentialsLock(lock: HeldCredentialsLock): void;
|
|
3
21
|
/**
|
|
4
22
|
* Runs a synchronous credentials transaction under the one process-wide and
|
|
5
23
|
* cross-process lock. Exported so real-process fixtures can hold the production
|
|
@@ -11,7 +29,7 @@ export declare function withCredentialsTransactionLock<T>(operation: () => T): T
|
|
|
11
29
|
* synchronous credential writes are admitted only from this transaction's
|
|
12
30
|
* async execution context; unrelated same-process work must wait or fail.
|
|
13
31
|
*/
|
|
14
|
-
export declare function withCredentialsTransactionLockAsync<T>(operation: () => Promise<T>): Promise<T>;
|
|
32
|
+
export declare function withCredentialsTransactionLockAsync<T>(operation: () => Promise<T>, acquire?: () => HeldCredentialsLock | Promise<HeldCredentialsLock>): Promise<T>;
|
|
15
33
|
export declare function loadCredentialsConfig(): StoredCredentialsV2 | StoredCredentialsV3 | null;
|
|
16
34
|
export declare function getServerCredentials(baseUrl: string): ServerCredentials | null;
|
|
17
35
|
export declare function saveServerCredentials(baseUrl: string, credentials: ServerCredentials): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAoBA,OAAO,EACL,iBAAiB,EAEjB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
|