@loomcycle/client 1.124.0 → 1.126.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +158 -0
- package/dist/cjs/client-tools.js +28 -5
- package/dist/cjs/client.js +310 -10
- package/dist/cjs/device-login.js +146 -0
- package/dist/cjs/errors.js +40 -1
- package/dist/cjs/fetch-helpers.js +31 -0
- package/dist/cjs/index.js +35 -1
- package/dist/cjs/oauth.js +400 -0
- package/dist/client-tools.d.ts +6 -2
- package/dist/client-tools.js +28 -5
- package/dist/client.d.ts +226 -4
- package/dist/client.js +311 -11
- package/dist/device-login.d.ts +12 -0
- package/dist/device-login.js +143 -0
- package/dist/errors.d.ts +36 -0
- package/dist/errors.js +37 -0
- package/dist/fetch-helpers.d.ts +8 -0
- package/dist/fetch-helpers.js +30 -0
- package/dist/index.d.ts +31 -2
- package/dist/index.js +29 -1
- package/dist/oauth.d.ts +131 -0
- package/dist/oauth.js +393 -0
- package/dist/types.d.ts +593 -12
- package/package.json +1 -1
package/dist/fetch-helpers.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* Method-level code in client.ts stays focused on URL + body shape;
|
|
10
10
|
* the boring fetch + error-translation machinery lives here.
|
|
11
11
|
*/
|
|
12
|
+
import type { TokenProvider } from "./types.js";
|
|
12
13
|
/**
|
|
13
14
|
* @internal — not part of @loomcycle/client's public API surface.
|
|
14
15
|
*
|
|
@@ -28,6 +29,13 @@ export interface _FetchContext {
|
|
|
28
29
|
authToken: string | undefined;
|
|
29
30
|
fetchImpl: typeof fetch;
|
|
30
31
|
}
|
|
32
|
+
/** authorizedFetch wraps a fetch so every request carries the provider's
|
|
33
|
+
* current bearer (replacing whatever Authorization the caller set), and a
|
|
34
|
+
* 401 is retried once with the token `onUnauthorized` hands back — never
|
|
35
|
+
* twice, so a token the server keeps refusing cannot loop. A request whose
|
|
36
|
+
* body is a stream is not retried: the stream was consumed by the first
|
|
37
|
+
* send. */
|
|
38
|
+
export declare function authorizedFetch(inner: typeof fetch, provider: TokenProvider): typeof fetch;
|
|
31
39
|
/** authHeaders builds the standard request header set: JSON Accept
|
|
32
40
|
* + Bearer token when the client was constructed with one. The
|
|
33
41
|
* caller adds Content-Type when posting a body. */
|
package/dist/fetch-helpers.js
CHANGED
|
@@ -10,6 +10,36 @@
|
|
|
10
10
|
* the boring fetch + error-translation machinery lives here.
|
|
11
11
|
*/
|
|
12
12
|
import { AclDeniedError, AgentIDInUseError, AgentNotFoundError, AlreadyPausingError, AuthError, BackpressureError, ChannelCursorRegressionError, InsufficientScopeError, InvalidArgumentError, LoomcycleError, NotFoundError, NotPausedError, PauseNotConfiguredError, PerUserQuotaExhaustedError, PromptTooLargeError, RateLimitedError, RequestTooLargeError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, TokenLimitExceededError, UnavailableError, } from "./errors.js";
|
|
13
|
+
/** authorizedFetch wraps a fetch so every request carries the provider's
|
|
14
|
+
* current bearer (replacing whatever Authorization the caller set), and a
|
|
15
|
+
* 401 is retried once with the token `onUnauthorized` hands back — never
|
|
16
|
+
* twice, so a token the server keeps refusing cannot loop. A request whose
|
|
17
|
+
* body is a stream is not retried: the stream was consumed by the first
|
|
18
|
+
* send. */
|
|
19
|
+
export function authorizedFetch(inner, provider) {
|
|
20
|
+
return async (input, init) => {
|
|
21
|
+
const token = await provider.getToken();
|
|
22
|
+
const first = await inner(input, withBearer(init, token));
|
|
23
|
+
if (first.status !== 401 || !provider.onUnauthorized || !replayableBody(init?.body))
|
|
24
|
+
return first;
|
|
25
|
+
const fresh = await provider.onUnauthorized(token);
|
|
26
|
+
if (!fresh || fresh === token)
|
|
27
|
+
return first;
|
|
28
|
+
await first.body?.cancel().catch(() => undefined);
|
|
29
|
+
return inner(input, withBearer(init, fresh));
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function withBearer(init, token) {
|
|
33
|
+
const headers = new Headers(init?.headers);
|
|
34
|
+
if (token)
|
|
35
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
36
|
+
else
|
|
37
|
+
headers.delete("Authorization");
|
|
38
|
+
return { ...init, headers };
|
|
39
|
+
}
|
|
40
|
+
function replayableBody(body) {
|
|
41
|
+
return !(typeof ReadableStream !== "undefined" && body instanceof ReadableStream);
|
|
42
|
+
}
|
|
13
43
|
/** authHeaders builds the standard request header set: JSON Accept
|
|
14
44
|
* + Bearer token when the client was constructed with one. The
|
|
15
45
|
* caller adds Content-Type when posting a body. */
|
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,20 @@
|
|
|
27
27
|
* mintUserToken(subject, opts?): Promise<MintedUserToken> // delegated token
|
|
28
28
|
* listUserTokens(subject, opts?): Promise<ListUserTokensResponse>
|
|
29
29
|
* revokeUserToken(subject, defId, opts?): Promise<{def_id, retired_at}>
|
|
30
|
+
* approveUser(subject, opts?): Promise<UserRecord> // pending → active (RFC FA)
|
|
31
|
+
* listUserIdentities(subject, opts?): Promise<UserIdentitiesResponse>
|
|
32
|
+
* unlinkUserIdentity(subject, gate, opts?): Promise<void>
|
|
33
|
+
*
|
|
34
|
+
* // Sign-in gates + the password gate's management API (RFC FA)
|
|
35
|
+
* listAuthGates(opts?): Promise<AuthGateListResponse> // admin token only
|
|
36
|
+
* createInvite(gate, body, opts?): Promise<CreatedInvite> // one-time link, shown once
|
|
37
|
+
* listInvites(gate, opts?): Promise<AuthInviteListResponse>
|
|
38
|
+
* revokeInvite(gate, inviteId, opts?): Promise<void>
|
|
39
|
+
* createPasswordReset(gate, subject, opts?): Promise<CreatedPasswordReset>
|
|
40
|
+
* removeGateCredentials(gate, subject, opts?): Promise<void>
|
|
41
|
+
* renameGateLogin(gate, subject, login, opts?): Promise<{subject, login}>
|
|
42
|
+
* listGateIdentities(gate, subject, opts?): Promise<GateIdentitiesResponse>
|
|
43
|
+
* getGateTenantStatus(gate, opts?): Promise<GateTenantStatus>
|
|
30
44
|
* runnableAgents(opts?): Promise<RunnableAgentsResponse> // RFC BY (v1.51.0) — agents I can run
|
|
31
45
|
* whoami(): Promise<WhoamiResponse> // RFC L principal (v0.17.0)
|
|
32
46
|
*
|
|
@@ -115,6 +129,19 @@
|
|
|
115
129
|
* listVolumes(): Promise<PersistentVolumesResponse>
|
|
116
130
|
* listEphemeralVolumes(): Promise<EphemeralVolumesResponse>
|
|
117
131
|
*
|
|
132
|
+
* // App clients (RFC FL ClientDef; tenant operator or admin)
|
|
133
|
+
* clientDef(input): Promise<unknown> // POST /v1/_clientdef
|
|
134
|
+
* createClientDef / updateClientDef(name, client, opts?): Promise<ClientDefRecord>
|
|
135
|
+
* getClientDef({name | def_id}): Promise<AppClientEntry>
|
|
136
|
+
* listClientDefs(opts?): Promise<ClientDefListResponse>
|
|
137
|
+
* retireClientDef(name): Promise<ClientDefRetireResult>
|
|
138
|
+
* verifyClientDef(name, {contentSha256}?): Promise<ClientDefVerifyResult>
|
|
139
|
+
* listClientDefNames(opts?): Promise<ClientDefNamesResponse> // GET /v1/_clientdef/names
|
|
140
|
+
*
|
|
141
|
+
* // App sign-in (RFC FL) — also standalone as `new LoomcycleOAuth(...)`
|
|
142
|
+
* oauth: LoomcycleOAuth // beginAuthorize / completeAuthorize / refresh / revoke / discover
|
|
143
|
+
* new LoomcycleClient({ tokenProvider: new OAuthTokenProvider(...) }) // refreshes on its own
|
|
144
|
+
*
|
|
118
145
|
* // Agent Teams (RFC AP — TeamDef substrate; tenant-confined)
|
|
119
146
|
* listTeams(): Promise<ListTeamsResponse>
|
|
120
147
|
* renderTeamDiagram(name, opts?): Promise<TeamDiagram>
|
|
@@ -187,5 +214,7 @@ export { verifyLoomcycleSignature, verifyLoomcycleDelivery } from "./signature.j
|
|
|
187
214
|
export type { VerifySignatureOptions, VerifiedDelivery } from "./signature.js";
|
|
188
215
|
export { ClientToolHost, clientToolsURL, CLIENT_TOOL_SUBPROTOCOL } from "./client-tools.js";
|
|
189
216
|
export type { ClientToolSchema, ClientToolInvocation, ConnectClientToolsOptions, WebSocketLike, WebSocketCtor, } from "./client-tools.js";
|
|
190
|
-
export
|
|
191
|
-
export {
|
|
217
|
+
export { LoomcycleOAuth, OAuthTokenProvider, parseAuthorizeResponse, pkceChallenge } from "./oauth.js";
|
|
218
|
+
export type { LoomcycleOAuthOptions, OAuthTokenProviderOptions } from "./oauth.js";
|
|
219
|
+
export type { AgentEvent, ClientOptions, ContinueOptions, EventType, HostWidening, ImageMediaType, ParentContext, PromptContent, PromptSegment, RetryInfo, RunOptions, RunOverrideOptions, SamplingOptions, CompactionOptions, ContextOptions, ToolUse, Usage, CallTiming, Agent, AgentStatus, AwaitedState, AgentUsage, RunResult, RunSpec, RunSpecTeam, ConfiguredRun, ConfiguredRunPatch, ToolChoiceOptions, OutputFormatOptions, CancelAgentResult, ListAgentsResponse, ListUserAgentsOptions, AgentList, WalkRunsPage, RunBatchOptions, RunBatchResult, SpawnRunResult, CompactRunResult, RunTreeDeletion, RunTreeNotReached, DirectoryBudget, DirectoryInspection, DirectoryTenant, DirectoryUser, ErasureAccess, ErasureReport, ErasureResidue, ErasureResult, ErasureTier, ErasureTokenRef, CancelTurnResult, ReviewRunResult, ReplaySessionResult, TranscriptEvent, TranscriptResponse, HealthResponse, ListUsersResponse, UserSummary, UserStatus, UserRecord, CreateUserBody, UpdateUserBody, MintedUserToken, TokenRestrictions, UserTokenMeta, ListUserTokensResponse, UserIdentity, UserIdentitiesResponse, AuthGateKind, AuthGate, AuthGateKey, AuthGateRemoval, AuthGateProbe, AuthGateListResponse, CreateInviteBody, CreatedInvite, AuthInviteState, AuthInvite, AuthInviteListResponse, CreatedPasswordReset, GateIdentity, GateIdentitiesResponse, GateTenantStatus, RunnableAgent, RunnableAgentsResponse, WhoamiResponse, WhoamiEffective, WhoamiAuth, PauseResult, RetentionOverride, ResumeResult, RuntimeStateResponse, RuntimeStateStatus, ResolverMatrix, ResolverModelStatus, ResolverProviderAvailability, CreateSnapshotOptions, SnapshotCreateResponse, SnapshotDescriptor, SnapshotEnvelope, SnapshotListResponse, SnapshotRestoreResponse, MemoryEntriesResponse, MemoryEntry, MemoryEntryResponse, MemoryScopeIDsResponse, MemoryScopeIDSummary, MemoryScopeKind, MemoryScopesResponse, MemorySearchDocumentFilter, MemorySearchInput, MemorySource, MemoryWhen, MemoryTimeFilter, MemorySearchEntry, MemorySearchResponse, MemoryEmbedModelStats, MemoryEmbedStatsResponse, MemoryReembedConfigured, MemoryReembedResponse, MemoryBackfillResponse, MemoryPurgeResponse, InterruptListResponse, InterruptRow, InterruptStatus, ResolveInterruptOptions, ChannelHookCall, ChannelHookResult, HookFailMode, HookPhase, HookToolCall, HookToolResult, PostHookCall, PostHookResult, PreHookCall, PreHookResult, SubstrateToolInput, SubstrateToolResponse, TeamNameSummary, ListTeamsResponse, TeamDiagram, CreatedTeam, PromotedTeam, RetiredTeam, TeamDefDetail, TeamVerification, TeamDraft, TeamDraftVerification, TeamIssue, TeamIssueKind, TeamVersion, TeamVersionList, TeamBreakpoints, TeamRunDetached, TeamRunResult, TeamRunTarget, CreateTeamOptions, ForkTeamOptions, DefNameSummary, DefNamesResponse, OperatorTokenDefNameSummary, OperatorTokenDefNamesResponse, ScheduleListEntry, ScheduleListResponse, ScheduleActiveRun, ScheduleStateView, ScheduleRunNowResult, SchedulePauseResult, ModelAlias, ModelAliasesResponse, RoutingResponse, RoutingUserTier, RoutingTier, RoutingCandidate, RoutingThroughput, RoutingProvider, SearchRoutingProvider, RoutingEmbedder, RoutingDecision, RoutingDecisionModel, ProviderModelsResponse, TeamRunStep, TeamDecisionHandler, TeamDecisionQuestion, TeamDecisionAnswer, PathToolInput, PathToolResponse, DocumentToolInput, DocumentToolResponse, DocumentSearchFilter, DocumentSearchHit, DocumentSearchResult, DocumentRelatedResult, HistoryToolInput, HistoryToolResponse, EvaluationEmitterRole, EvaluationSubmitInput, EvaluationGetInput, EvaluationListForRunInput, EvaluationListForDefInput, EvaluationAggregateInput, EvaluationInput, EvaluationSubmitResult, EvaluationRecord, EvaluationListForRunResult, EvaluationListForDefResult, EvaluationScoreStats, EvaluationAggregate, VolumeMode, PersistentVolumeEntry, PersistentVolumesResponse, EphemeralVolumeEntry, EphemeralVolumesResponse, SystemPromptPayload, UserInputPayload, ChannelDescriptor, ListChannelsResponse, RunStateEvent, RunStateStreamClose, RunStateStreamItem, RunStateStreamOpen, StreamUserRunStatesOptions, ChangeFeedError, ChangeFeedFrame, ChangeFeedStatus, EmbedderHealth, MemoryChange, MemoryChangeScope, MemoryChangeType, StreamChangesOptions, AckChannelOptions, ChannelAckResult, ChannelMessageItem, ChannelPeekResult, ListTeamChannelsOptions, PeekTeamChannelOptions, ReleaseTeamChannelOptions, TeamChannelReleaseResult, TeamChannelDeclaredIn, TeamChannelDescriptor, TeamChannelPeekResult, TeamChannelsResult, ChannelPublishResult, ChannelPurgeResult, ChannelReleaseResult, ChannelScope, ChannelSubscribeResult, PeekChannelOptions, PublishChannelOptions, SubscribeChannelOptions, AwaitChannelsOptions, BroadcastChannelsOptions, ChannelAwaitEntry, ChannelAwaitMode, ChannelAwaitResult, ChannelBroadcastEntry, ChannelBroadcastResult, CreateChannelOptions, ReleaseChannelOptions, UpdateChannelOptions, SetMemoryEntryOptions, SetMemoryEntryResponse, AgentDefRowResponse, AgentDefVerifyResult, SkillDefVerifyResult, EnsureMcpServerOptions, EnsureMcpServerResult, MCPServerDefRowResponse, MCPServerDefVerifyResult, AgentDefOverlay, AgentRouting, AgentChannelACL, AgentInterruptionACL, AgentDecision, MemoryRerank, AgentSampling, AgentCompaction, AgentTranscription, AgentSpeech, AgentContext, TierCandidate, CoreBlock, HookEvent, InlineWebhook, HookEntry, EventHooks, ToolEntry, ToolHooksByTool, EnsureCodeAgentOptions, EnsureCodeAgentResult, CreateDefOptions, ForkDefOptions, EnsureHookDefOptions, EnsureHookDefResult, HookDefBody, HookDefForkOverlay, HookDefInput, HookDefMatch, HookDefOverlay, HookDefRowResponse, HookDefVerifyResult, ScheduleDefInput, ScheduleDefOverlay, ScheduleDefRowResponse, ScheduledRunHook, ScheduledRunPromptContent, ScheduledRunPromptSegment, WebhookDefAuth, WebhookDefFilter, WebhookDefInput, WebhookDefOverlay, WebhookDefRateLimit, WebhookDefRowResponse, WebhookDefDeliveries, WebhookDefSyncResponse, LibraryAgentDefinition, LibraryEntry, LibraryListResponse, LibraryMcpServerDefinition, LibrarySkillDefinition, LLMChatContent, LLMChatMessage, LLMChatOptions, LLMChatResponse, LLMChatStreamDelta, LLMChatStreamItem, LLMChatToolCall, LLMChatUsage, LLMTool, LLMEmbeddingItem, LLMEmbeddingsOptions, LLMEmbeddingsResponse, LLMEmbeddingsUsage, UsageDimension, UsageBucket, UsageAggregate, UsageReportResponse, CapabilityInertInfo, LimitInfo, FileCapturedInfo, TranscriptionInfo, AdmissionInfo, ErrorInfo, CallFormat, CallRef, HookDecisionInfo, TeamDecisionInfo, OverrideInfo, FallbackInfo, InterruptionEventInfo, SpawnChildInfo, TurnCancelledInfo, ChannelEventInfo, ContextCompactionInfo, ContextRecapInfo, ContextStateInfo, ContextExhaustedInfo, ContextTierVerdict, ContextDistillDeclinedInfo, EffectiveConfigResponse, RunFileInput, RunFileImportSource, RunFileImportHeading, RunInboxDownload, EffectiveConfigSource, EffectiveValue, InertContextSetting, AgentOverridableResponse, OverridableField, OverrideLockReason, RetuneRunResponse, RunConfigRecord, SubagentHoldInfo, RunConfigResponse, RunPromptResponse, RunPromptSnapshot, PromptBlock, TokenLimit, TokenLimitsResponse, ConfigResponse, ConfigProvider, ConfigModel, ConfigSearch, ConfigInstance, SetTokenLimitRequest, CredentialScope, CredentialMeta, CredentialListResponse, CryptoKeyVersion, CryptoKeyExport, CryptoKeyType, CryptoKeyEncoding, CryptoKeyBackend, CryptoKeyExternal, CryptoOp, CryptoRequestBase, CryptoKeyRef, CryptoEncryptRequest, CryptoDecryptRequest, CryptoRewrapRequest, CryptoMacRequest, CryptoVerifyMacRequest, CryptoSignRequest, CryptoVerifyRequest, CryptoPublicKeyRequest, CryptoTotpRequest, CryptoHashRequest, CryptoRandomRequest, CryptoHashPasswordRequest, CryptoVerifyPasswordRequest, CryptoRequest, CryptoEncryptResult, CryptoDecryptResult, CryptoRewrapResult, CryptoMacResult, CryptoVerifyResult, CryptoSignResult, CryptoPublicJWK, CryptoPublicKeyResult, CryptoTotpResult, CryptoHashResult, CryptoRandomResult, CryptoHashPasswordResult, CryptoVerifyPasswordResult, CryptoResultByOp, CryptoResult, DecideRequest, DecideResponse, DecisionQuestion, DecisionChoiceQuestion, DecisionNoulQuestion, DecisionScoreQuestion, DecisionAnswer, DecisionChoiceAnswer, DecisionNoulAnswer, DecisionScoreAnswer, DecisionModel, DecisionModelsResponse, AclMode, AclSource, AclEffect, AclSubjectKind, AclCondition, AclRule, AclList, AclDefRow, AclDefListResponse, AclDefNamesResponse, AclValidateResult, AclCatalogType, AclCatalog, AclDefOp, AclDefInput, GroupRow, GroupMemberKind, GroupMember, GroupListResponse, GroupDetail, GroupEffective, CreateGroupBody, GroupMemberChange, AclBinding, AclBindingListResponse, CreateAclBindingBody, AuthzReason, AuthzDecision, AuthzRequestContext, AuthzEvaluationRequest, AuthzEvaluationsSemantic, AuthzEvaluationsRequest, AuthzEvaluationsResponse, AuthzTrace, AuthzAppliedBinding, AuthzExplainResponse, AuthzDraftBinding, AuthzSimulateRequest, AuthzSimulateResult, AuthzSimulateResponse, OAuthServerMetadata, OAuthTokenResponse, OAuthTokenSet, BeginAuthorizeOptions, AuthorizeRequest, AuthorizeResponseParams, CompleteAuthorizeOptions, RefreshTokenOptions, RevokeTokenOptions, TokenProvider, AppClientRefresh, AppClientConfig, ClientDefInput, ClientDefRecord, ConfigAppClient, AppClientEntry, ClientDefListResponse, ClientDefVerifyResult, ClientDefRetireResult, ClientDefNameSummary, ClientDefNamesResponse, DeviceLoginPrompt, DeviceLoginOptions, DeviceLoginResult, } from "./types.js";
|
|
220
|
+
export { AclDeniedError, AgentIDInUseError, AgentNotFoundError, AlreadyPausingError, AuthError, BackpressureError, DeviceLoginError, NotFoundError, InsufficientScopeError, InvalidArgumentError, ChannelCursorRegressionError, LoomcycleError, NotPausedError, OAuthError, PauseNotConfiguredError, PerUserQuotaExhaustedError, PromptTooLargeError, RateLimitedError, RequestTooLargeError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, TokenLimitExceededError, UnavailableError, } from "./errors.js";
|
package/dist/index.js
CHANGED
|
@@ -27,6 +27,20 @@
|
|
|
27
27
|
* mintUserToken(subject, opts?): Promise<MintedUserToken> // delegated token
|
|
28
28
|
* listUserTokens(subject, opts?): Promise<ListUserTokensResponse>
|
|
29
29
|
* revokeUserToken(subject, defId, opts?): Promise<{def_id, retired_at}>
|
|
30
|
+
* approveUser(subject, opts?): Promise<UserRecord> // pending → active (RFC FA)
|
|
31
|
+
* listUserIdentities(subject, opts?): Promise<UserIdentitiesResponse>
|
|
32
|
+
* unlinkUserIdentity(subject, gate, opts?): Promise<void>
|
|
33
|
+
*
|
|
34
|
+
* // Sign-in gates + the password gate's management API (RFC FA)
|
|
35
|
+
* listAuthGates(opts?): Promise<AuthGateListResponse> // admin token only
|
|
36
|
+
* createInvite(gate, body, opts?): Promise<CreatedInvite> // one-time link, shown once
|
|
37
|
+
* listInvites(gate, opts?): Promise<AuthInviteListResponse>
|
|
38
|
+
* revokeInvite(gate, inviteId, opts?): Promise<void>
|
|
39
|
+
* createPasswordReset(gate, subject, opts?): Promise<CreatedPasswordReset>
|
|
40
|
+
* removeGateCredentials(gate, subject, opts?): Promise<void>
|
|
41
|
+
* renameGateLogin(gate, subject, login, opts?): Promise<{subject, login}>
|
|
42
|
+
* listGateIdentities(gate, subject, opts?): Promise<GateIdentitiesResponse>
|
|
43
|
+
* getGateTenantStatus(gate, opts?): Promise<GateTenantStatus>
|
|
30
44
|
* runnableAgents(opts?): Promise<RunnableAgentsResponse> // RFC BY (v1.51.0) — agents I can run
|
|
31
45
|
* whoami(): Promise<WhoamiResponse> // RFC L principal (v0.17.0)
|
|
32
46
|
*
|
|
@@ -115,6 +129,19 @@
|
|
|
115
129
|
* listVolumes(): Promise<PersistentVolumesResponse>
|
|
116
130
|
* listEphemeralVolumes(): Promise<EphemeralVolumesResponse>
|
|
117
131
|
*
|
|
132
|
+
* // App clients (RFC FL ClientDef; tenant operator or admin)
|
|
133
|
+
* clientDef(input): Promise<unknown> // POST /v1/_clientdef
|
|
134
|
+
* createClientDef / updateClientDef(name, client, opts?): Promise<ClientDefRecord>
|
|
135
|
+
* getClientDef({name | def_id}): Promise<AppClientEntry>
|
|
136
|
+
* listClientDefs(opts?): Promise<ClientDefListResponse>
|
|
137
|
+
* retireClientDef(name): Promise<ClientDefRetireResult>
|
|
138
|
+
* verifyClientDef(name, {contentSha256}?): Promise<ClientDefVerifyResult>
|
|
139
|
+
* listClientDefNames(opts?): Promise<ClientDefNamesResponse> // GET /v1/_clientdef/names
|
|
140
|
+
*
|
|
141
|
+
* // App sign-in (RFC FL) — also standalone as `new LoomcycleOAuth(...)`
|
|
142
|
+
* oauth: LoomcycleOAuth // beginAuthorize / completeAuthorize / refresh / revoke / discover
|
|
143
|
+
* new LoomcycleClient({ tokenProvider: new OAuthTokenProvider(...) }) // refreshes on its own
|
|
144
|
+
*
|
|
118
145
|
* // Agent Teams (RFC AP — TeamDef substrate; tenant-confined)
|
|
119
146
|
* listTeams(): Promise<ListTeamsResponse>
|
|
120
147
|
* renderTeamDiagram(name, opts?): Promise<TeamDiagram>
|
|
@@ -184,4 +211,5 @@ export { LoomcycleClient } from "./client.js";
|
|
|
184
211
|
export { InteractiveSession } from "./interactive.js";
|
|
185
212
|
export { verifyLoomcycleSignature, verifyLoomcycleDelivery } from "./signature.js";
|
|
186
213
|
export { ClientToolHost, clientToolsURL, CLIENT_TOOL_SUBPROTOCOL } from "./client-tools.js";
|
|
187
|
-
export {
|
|
214
|
+
export { LoomcycleOAuth, OAuthTokenProvider, parseAuthorizeResponse, pkceChallenge } from "./oauth.js";
|
|
215
|
+
export { AclDeniedError, AgentIDInUseError, AgentNotFoundError, AlreadyPausingError, AuthError, BackpressureError, DeviceLoginError, NotFoundError, InsufficientScopeError, InvalidArgumentError, ChannelCursorRegressionError, LoomcycleError, NotPausedError, OAuthError, PauseNotConfiguredError, PerUserQuotaExhaustedError, PromptTooLargeError, RateLimitedError, RequestTooLargeError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, TokenLimitExceededError, UnavailableError, } from "./errors.js";
|
package/dist/oauth.d.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { OAuthError } from "./errors.js";
|
|
2
|
+
import type { AuthorizeRequest, AuthorizeResponseParams, BeginAuthorizeOptions, CompleteAuthorizeOptions, OAuthServerMetadata, OAuthTokenSet, RefreshTokenOptions, RevokeTokenOptions, TokenProvider } from "./types.js";
|
|
3
|
+
/** Options for {@link LoomcycleOAuth}. */
|
|
4
|
+
export interface LoomcycleOAuthOptions {
|
|
5
|
+
/** loomcycle's address as the person's browser reaches it, e.g.
|
|
6
|
+
* `https://loom.example.com`. Defaults to http://127.0.0.1:8787. */
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
/** Custom fetch (tests, Tauri's HTTP plugin); defaults to global `fetch`. */
|
|
9
|
+
fetch?: typeof fetch;
|
|
10
|
+
/** Web Crypto; defaults to `globalThis.crypto` (browsers, Node 19+). On
|
|
11
|
+
* Node 18 pass `require("node:crypto").webcrypto`. */
|
|
12
|
+
crypto?: Crypto;
|
|
13
|
+
/** The server's issuer identifier, when the app knows it. A redirect's
|
|
14
|
+
* `iss` is compared with it; without it, the issuer is discovered from
|
|
15
|
+
* the server's metadata the first time a redirect carries `iss`. */
|
|
16
|
+
issuer?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The app sign-in helper. Construct one per loomcycle server.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* const oauth = new LoomcycleOAuth({ baseUrl: "https://loom.example.com" });
|
|
23
|
+
* // 1. Start: keep verifier + state in session storage, then navigate.
|
|
24
|
+
* const req = await oauth.beginAuthorize({ clientId: "loomboard", redirectUri });
|
|
25
|
+
* sessionStorage.setItem("lc_pkce", JSON.stringify({ verifier: req.verifier, state: req.state }));
|
|
26
|
+
* location.assign(req.url);
|
|
27
|
+
* // 2. Back on redirectUri:
|
|
28
|
+
* const saved = JSON.parse(sessionStorage.getItem("lc_pkce")!);
|
|
29
|
+
* const tokens = await oauth.completeAuthorize({
|
|
30
|
+
* ...parseAuthorizeResponse(location.href),
|
|
31
|
+
* expectedState: saved.state, verifier: saved.verifier, clientId: "loomboard", redirectUri,
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare class LoomcycleOAuth {
|
|
36
|
+
private readonly baseUrl;
|
|
37
|
+
private readonly fetchImpl;
|
|
38
|
+
private readonly cryptoImpl?;
|
|
39
|
+
private readonly issuer?;
|
|
40
|
+
private metadata?;
|
|
41
|
+
constructor(opts?: LoomcycleOAuthOptions);
|
|
42
|
+
/** Start a sign-in: a fresh PKCE verifier, its S256 challenge, a state,
|
|
43
|
+
* and the authorize URL to send the person to. Nothing is sent to the
|
|
44
|
+
* server. */
|
|
45
|
+
beginAuthorize(opts: BeginAuthorizeOptions): Promise<AuthorizeRequest>;
|
|
46
|
+
/** Finish a sign-in from the redirect's parameters (see
|
|
47
|
+
* {@link parseAuthorizeResponse}). In order: the `state` must be the one
|
|
48
|
+
* this sign-in sent, an `iss` must name this server (RFC 9207), an
|
|
49
|
+
* `error` is thrown as an {@link OAuthError}, and only then is the code
|
|
50
|
+
* exchanged. */
|
|
51
|
+
completeAuthorize(opts: CompleteAuthorizeOptions): Promise<OAuthTokenSet>;
|
|
52
|
+
/** Trade a refresh token for a new token set. The refresh token is spent:
|
|
53
|
+
* persist the returned one before anything else uses the old. A spent
|
|
54
|
+
* token presented again ends the whole sign-in. */
|
|
55
|
+
refresh(opts: RefreshTokenOptions): Promise<OAuthTokenSet>;
|
|
56
|
+
/** Sign out (RFC 7009): a refresh token ends the whole sign-in, an access
|
|
57
|
+
* token ends that token. The server answers the same for a token it does
|
|
58
|
+
* not know, so this resolves unless the request itself failed. */
|
|
59
|
+
revoke(opts: RevokeTokenOptions): Promise<void>;
|
|
60
|
+
/** The server's authorization server metadata (RFC 8414). Cached after the
|
|
61
|
+
* first success. Fails with a 404 when the server does not know its public
|
|
62
|
+
* address (`LOOMCYCLE_PUBLIC_URL` unset). */
|
|
63
|
+
discover(opts?: {
|
|
64
|
+
signal?: AbortSignal;
|
|
65
|
+
}): Promise<OAuthServerMetadata>;
|
|
66
|
+
private fetchMetadata;
|
|
67
|
+
private tokenRequest;
|
|
68
|
+
/** POST a form: parameters in the body, never the URL; no bearer and no
|
|
69
|
+
* cookie (the code or the refresh token is the credential); only
|
|
70
|
+
* CORS-safelisted headers, so a browser sends it without a preflight. */
|
|
71
|
+
private postForm;
|
|
72
|
+
private webCrypto;
|
|
73
|
+
}
|
|
74
|
+
/** Read the authorization response parameters from the redirect URL (its
|
|
75
|
+
* query). Pass the result to {@link LoomcycleOAuth.completeAuthorize}. */
|
|
76
|
+
export declare function parseAuthorizeResponse(url: string | URL): AuthorizeResponseParams;
|
|
77
|
+
/** The PKCE S256 code challenge of a verifier (RFC 7636 §4.2):
|
|
78
|
+
* BASE64URL(SHA-256(ASCII(verifier))). */
|
|
79
|
+
export declare function pkceChallenge(verifier: string, cryptoImpl?: Crypto): Promise<string>;
|
|
80
|
+
/** Options for {@link OAuthTokenProvider}. */
|
|
81
|
+
export interface OAuthTokenProviderOptions {
|
|
82
|
+
/** The helper for the server that issued the tokens. */
|
|
83
|
+
oauth: LoomcycleOAuth;
|
|
84
|
+
clientId: string;
|
|
85
|
+
/** The current token set (from completeAuthorize, or persisted). */
|
|
86
|
+
tokens: OAuthTokenSet;
|
|
87
|
+
/** Called with every new token set, before the token is used. Persist it:
|
|
88
|
+
* the refresh token it replaced is spent. A throw fails the request that
|
|
89
|
+
* caused the refresh; the new set is kept in memory regardless. */
|
|
90
|
+
onTokens?: (tokens: OAuthTokenSet) => void | Promise<void>;
|
|
91
|
+
/** Called once when the sign-in ends: the server refused the refresh token
|
|
92
|
+
* (revoked, expired, reused) or {@link OAuthTokenProvider.signOut} ran.
|
|
93
|
+
* Clear what you persisted and send the person to sign in again. */
|
|
94
|
+
onSignedOut?: (reason: OAuthError) => void;
|
|
95
|
+
/** Refresh this long before the access token expires (default 60 s). */
|
|
96
|
+
refreshSkewMs?: number;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* A {@link TokenProvider} over an app sign-in: hands out the access token,
|
|
100
|
+
* refreshes it before it expires and once after a 401, and shares one
|
|
101
|
+
* refresh between concurrent requests (two refreshes of the same refresh
|
|
102
|
+
* token would end the sign-in, since the server takes the second as a
|
|
103
|
+
* replay).
|
|
104
|
+
*
|
|
105
|
+
* One provider per sign-in: two providers — or two browser tabs — refreshing
|
|
106
|
+
* the same refresh token end it the same way.
|
|
107
|
+
*/
|
|
108
|
+
export declare class OAuthTokenProvider implements TokenProvider {
|
|
109
|
+
private readonly opts;
|
|
110
|
+
private current?;
|
|
111
|
+
private inflight?;
|
|
112
|
+
private ended?;
|
|
113
|
+
private readonly skew;
|
|
114
|
+
constructor(opts: OAuthTokenProviderOptions);
|
|
115
|
+
/** The current token set; undefined once signed out. */
|
|
116
|
+
get tokens(): OAuthTokenSet | undefined;
|
|
117
|
+
getToken(): Promise<string | undefined>;
|
|
118
|
+
onUnauthorized(rejected: string | undefined): Promise<string | undefined>;
|
|
119
|
+
/** Refresh now, sharing a refresh already under way. */
|
|
120
|
+
refresh(): Promise<OAuthTokenSet>;
|
|
121
|
+
/** End the sign-in: revoke the refresh token on the server (which also
|
|
122
|
+
* ends the access tokens it issued) and forget the tokens. Resolves even
|
|
123
|
+
* if the server could not be reached; the tokens are forgotten either
|
|
124
|
+
* way. */
|
|
125
|
+
signOut(opts?: {
|
|
126
|
+
signal?: AbortSignal;
|
|
127
|
+
}): Promise<void>;
|
|
128
|
+
private refreshOnce;
|
|
129
|
+
private doRefresh;
|
|
130
|
+
private end;
|
|
131
|
+
}
|