@hachej/boring-workspace 0.1.82 → 0.1.83
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-server.js +47 -10
- package/dist/server.d.ts +8 -1
- package/dist/server.js +49 -10
- package/dist/workspace.css +61 -17
- package/package.json +4 -4
package/dist/app-server.js
CHANGED
|
@@ -3330,20 +3330,28 @@ function mintWorkspaceBridgeRuntimeRefreshToken(options) {
|
|
|
3330
3330
|
});
|
|
3331
3331
|
}
|
|
3332
3332
|
function verifyWorkspaceBridgeRuntimeToken(token, options) {
|
|
3333
|
+
return authorizeWorkspaceBridgeRuntimeToken(
|
|
3334
|
+
verifyWorkspaceBridgeRuntimeTokenClaims(token, options),
|
|
3335
|
+
options.requiredCapabilities
|
|
3336
|
+
);
|
|
3337
|
+
}
|
|
3338
|
+
function verifyWorkspaceBridgeRuntimeTokenClaims(token, options) {
|
|
3333
3339
|
assertUsableSecret(options.secret);
|
|
3334
3340
|
const claims = parseAndVerifyToken(token, options.secret);
|
|
3335
3341
|
const now = Math.floor((options.nowMs ?? Date.now()) / 1e3);
|
|
3336
3342
|
ensureLiveTokenClaims(claims, now, WORKSPACE_BRIDGE_TOKEN_AUDIENCE, "Runtime bridge token");
|
|
3337
|
-
|
|
3338
|
-
|
|
3343
|
+
return { claims };
|
|
3344
|
+
}
|
|
3345
|
+
function authorizeWorkspaceBridgeRuntimeToken(verified, requiredCapabilities = []) {
|
|
3346
|
+
const missingCapability = requiredCapabilities.find(
|
|
3347
|
+
(capability) => !verified.claims.capabilities.includes(capability)
|
|
3339
3348
|
);
|
|
3340
3349
|
if (missingCapability) {
|
|
3341
3350
|
throw bridgeTokenError("BRIDGE_CAPABILITY_DENIED" /* CapabilityDenied */, "Runtime bridge token is missing a required capability");
|
|
3342
3351
|
}
|
|
3343
|
-
const runtimeClaims = claims;
|
|
3344
3352
|
return {
|
|
3345
|
-
claims:
|
|
3346
|
-
authContext: runtimeClaimsToBridgeAuthContext(
|
|
3353
|
+
claims: verified.claims,
|
|
3354
|
+
authContext: runtimeClaimsToBridgeAuthContext(verified.claims)
|
|
3347
3355
|
};
|
|
3348
3356
|
}
|
|
3349
3357
|
function verifyWorkspaceBridgeRuntimeRefreshToken(token, options) {
|
|
@@ -3565,14 +3573,25 @@ function workspaceBridgeHttpRoutes(app, opts, done) {
|
|
|
3565
3573
|
return sendBridgeError(reply, 400, void 0, "BRIDGE_SCHEMA_INVALID" /* SchemaInvalid */, "WorkspaceBridge request body is invalid");
|
|
3566
3574
|
}
|
|
3567
3575
|
const body = { ...parsed.data, input: parsed.data.input ?? {} };
|
|
3576
|
+
const authHeader = firstHeader(request.headers.authorization);
|
|
3577
|
+
const runtimeToken = authHeader?.startsWith("Bearer ") ? authHeader.slice("Bearer ".length) : void 0;
|
|
3578
|
+
let verifiedRuntimeToken;
|
|
3579
|
+
if (runtimeToken !== void 0 && opts.assertRuntimeWorkspaceScope) {
|
|
3580
|
+
try {
|
|
3581
|
+
verifiedRuntimeToken = resolveRuntimeClaims(runtimeToken, opts);
|
|
3582
|
+
} catch (err) {
|
|
3583
|
+
const bridgeError = isBridgeError(err) ? err : createWorkspaceBridgeError("BRIDGE_HANDLER_FAILED" /* HandlerFailed */, "WorkspaceBridge transport failed");
|
|
3584
|
+
return sendBridgeError(reply, statusForBridgeError(bridgeError.code), body.requestId, bridgeError.code, bridgeError.message);
|
|
3585
|
+
}
|
|
3586
|
+
await opts.assertRuntimeWorkspaceScope(request, verifiedRuntimeToken.claims);
|
|
3587
|
+
}
|
|
3568
3588
|
try {
|
|
3569
3589
|
const registry = await resolveRegistry(request, body, opts);
|
|
3570
3590
|
const definition = registry.getDefinition(body.op);
|
|
3571
3591
|
if (!definition) {
|
|
3572
3592
|
return sendBridgeError(reply, statusForBridgeError("BRIDGE_OP_NOT_FOUND" /* OpNotFound */), body.requestId, "BRIDGE_OP_NOT_FOUND" /* OpNotFound */, "WorkspaceBridge operation is not registered");
|
|
3573
3593
|
}
|
|
3574
|
-
const
|
|
3575
|
-
const authContext = authHeader?.startsWith("Bearer ") ? resolveRuntimeContext(authHeader.slice("Bearer ".length), opts, definition) : await resolveBrowserContext(request, opts, definition, body);
|
|
3594
|
+
const authContext = runtimeToken !== void 0 ? resolveRuntimeContext(runtimeToken, opts, definition, verifiedRuntimeToken) : await resolveBrowserContext(request, opts, definition, body);
|
|
3576
3595
|
const idempotencyStore = opts.getIdempotencyStore ? await opts.getIdempotencyStore(request, body) : opts.idempotencyStore;
|
|
3577
3596
|
const expectedWorkspaceId = opts.getOwnerWorkspaceId ? await opts.getOwnerWorkspaceId(request, body, authContext) : opts.ownerWorkspaceId;
|
|
3578
3597
|
const response = await runWithWorkspaceBridgeIdempotency(idempotencyStore, {
|
|
@@ -3595,12 +3614,21 @@ function workspaceBridgeHttpRoutes(app, opts, done) {
|
|
|
3595
3614
|
if (!opts.runtimeTokenSecret || !opts.runtimeRefreshTokenSecret) {
|
|
3596
3615
|
return sendBridgeError(reply, 401, void 0, "BRIDGE_AUTH_REQUIRED" /* AuthRequired */, "WorkspaceBridge token refresh is not configured");
|
|
3597
3616
|
}
|
|
3617
|
+
const nowMs = Date.now();
|
|
3618
|
+
let verified;
|
|
3598
3619
|
try {
|
|
3599
|
-
|
|
3600
|
-
const verified = verifyWorkspaceBridgeRuntimeRefreshToken(authHeader.slice("Bearer ".length), {
|
|
3620
|
+
verified = verifyWorkspaceBridgeRuntimeRefreshToken(authHeader.slice("Bearer ".length), {
|
|
3601
3621
|
secret: opts.runtimeRefreshTokenSecret,
|
|
3602
3622
|
nowMs
|
|
3603
3623
|
});
|
|
3624
|
+
} catch (err) {
|
|
3625
|
+
const bridgeError = isBridgeError(err) ? err : createWorkspaceBridgeError("BRIDGE_INVALID_TOKEN" /* InvalidToken */, "WorkspaceBridge refresh token is invalid");
|
|
3626
|
+
return sendBridgeError(reply, statusForBridgeError(bridgeError.code), void 0, bridgeError.code, bridgeError.message);
|
|
3627
|
+
}
|
|
3628
|
+
if (opts.assertRuntimeWorkspaceScope) {
|
|
3629
|
+
await opts.assertRuntimeWorkspaceScope(request, verified.claims);
|
|
3630
|
+
}
|
|
3631
|
+
try {
|
|
3604
3632
|
const store = opts.getRuntimeRefreshTokenStore ? await opts.getRuntimeRefreshTokenStore(request, verified.claims) ?? defaultRefreshTokenStore : defaultRefreshTokenStore;
|
|
3605
3633
|
const refreshUse = await store.recordUse({
|
|
3606
3634
|
jti: verified.claims.jti,
|
|
@@ -3643,7 +3671,10 @@ async function resolveRegistry(request, body, opts) {
|
|
|
3643
3671
|
}
|
|
3644
3672
|
return registry;
|
|
3645
3673
|
}
|
|
3646
|
-
function resolveRuntimeContext(token, opts, definition) {
|
|
3674
|
+
function resolveRuntimeContext(token, opts, definition, verified) {
|
|
3675
|
+
if (verified) {
|
|
3676
|
+
return authorizeWorkspaceBridgeRuntimeToken(verified, definition.requiredCapabilities).authContext;
|
|
3677
|
+
}
|
|
3647
3678
|
if (!opts.runtimeTokenSecret) {
|
|
3648
3679
|
throw createWorkspaceBridgeError("BRIDGE_AUTH_REQUIRED" /* AuthRequired */, "Runtime bridge token auth is not configured");
|
|
3649
3680
|
}
|
|
@@ -3652,6 +3683,12 @@ function resolveRuntimeContext(token, opts, definition) {
|
|
|
3652
3683
|
requiredCapabilities: definition.requiredCapabilities
|
|
3653
3684
|
}).authContext;
|
|
3654
3685
|
}
|
|
3686
|
+
function resolveRuntimeClaims(token, opts) {
|
|
3687
|
+
if (!opts.runtimeTokenSecret) {
|
|
3688
|
+
throw createWorkspaceBridgeError("BRIDGE_AUTH_REQUIRED" /* AuthRequired */, "Runtime bridge token auth is not configured");
|
|
3689
|
+
}
|
|
3690
|
+
return verifyWorkspaceBridgeRuntimeTokenClaims(token, { secret: opts.runtimeTokenSecret });
|
|
3691
|
+
}
|
|
3655
3692
|
async function resolveBrowserContext(request, opts, definition, body) {
|
|
3656
3693
|
if (!opts.browserAuthPolicy) {
|
|
3657
3694
|
throw createWorkspaceBridgeError("BRIDGE_AUTH_REQUIRED" /* AuthRequired */, "Browser bridge auth is not configured");
|
package/dist/server.d.ts
CHANGED
|
@@ -232,6 +232,7 @@ interface VerifyWorkspaceBridgeRuntimeTokenOptions {
|
|
|
232
232
|
nowMs?: number;
|
|
233
233
|
requiredCapabilities?: readonly string[];
|
|
234
234
|
}
|
|
235
|
+
type VerifyWorkspaceBridgeRuntimeTokenClaimsOptions = Omit<VerifyWorkspaceBridgeRuntimeTokenOptions, "requiredCapabilities">;
|
|
235
236
|
interface VerifyWorkspaceBridgeRuntimeRefreshTokenOptions {
|
|
236
237
|
secret: string;
|
|
237
238
|
nowMs?: number;
|
|
@@ -240,12 +241,17 @@ interface VerifiedWorkspaceBridgeRuntimeToken {
|
|
|
240
241
|
claims: WorkspaceBridgeRuntimeTokenClaims;
|
|
241
242
|
authContext: BridgeAuthContext;
|
|
242
243
|
}
|
|
244
|
+
interface VerifiedWorkspaceBridgeRuntimeTokenClaims {
|
|
245
|
+
claims: WorkspaceBridgeRuntimeTokenClaims;
|
|
246
|
+
}
|
|
243
247
|
interface VerifiedWorkspaceBridgeRuntimeRefreshToken {
|
|
244
248
|
claims: WorkspaceBridgeRuntimeRefreshTokenClaims;
|
|
245
249
|
}
|
|
246
250
|
declare function mintWorkspaceBridgeRuntimeToken(options: MintWorkspaceBridgeRuntimeTokenOptions): string;
|
|
247
251
|
declare function mintWorkspaceBridgeRuntimeRefreshToken(options: MintWorkspaceBridgeRuntimeRefreshTokenOptions): string;
|
|
248
252
|
declare function verifyWorkspaceBridgeRuntimeToken(token: string, options: VerifyWorkspaceBridgeRuntimeTokenOptions): VerifiedWorkspaceBridgeRuntimeToken;
|
|
253
|
+
declare function verifyWorkspaceBridgeRuntimeTokenClaims(token: string, options: VerifyWorkspaceBridgeRuntimeTokenClaimsOptions): VerifiedWorkspaceBridgeRuntimeTokenClaims;
|
|
254
|
+
declare function authorizeWorkspaceBridgeRuntimeToken(verified: VerifiedWorkspaceBridgeRuntimeTokenClaims, requiredCapabilities?: readonly string[]): VerifiedWorkspaceBridgeRuntimeToken;
|
|
249
255
|
declare function verifyWorkspaceBridgeRuntimeRefreshToken(token: string, options: VerifyWorkspaceBridgeRuntimeRefreshTokenOptions): VerifiedWorkspaceBridgeRuntimeRefreshToken;
|
|
250
256
|
declare function clampWorkspaceBridgeRuntimeTokenTtlMs(ttlMs: number | undefined): number | undefined;
|
|
251
257
|
declare function runtimeClaimsToBridgeAuthContext(claims: WorkspaceBridgeRuntimeTokenClaims): BridgeAuthContext;
|
|
@@ -289,6 +295,7 @@ interface WorkspaceBridgeHttpRoutesOptions {
|
|
|
289
295
|
runtimeRefreshTokenSecret?: string;
|
|
290
296
|
runtimeRefreshTokenStore?: WorkspaceBridgeRuntimeRefreshTokenStore;
|
|
291
297
|
getRuntimeRefreshTokenStore?: (request: FastifyRequest, claims: WorkspaceBridgeRuntimeRefreshTokenClaims) => WorkspaceBridgeRuntimeRefreshTokenStore | undefined | Promise<WorkspaceBridgeRuntimeRefreshTokenStore | undefined>;
|
|
298
|
+
assertRuntimeWorkspaceScope?: (request: FastifyRequest, claims: WorkspaceBridgeRuntimeTokenClaims | WorkspaceBridgeRuntimeRefreshTokenClaims) => void | Promise<void>;
|
|
292
299
|
refreshTokenRateLimit?: {
|
|
293
300
|
maxUses?: number;
|
|
294
301
|
windowMs?: number;
|
|
@@ -622,4 +629,4 @@ interface RuntimeBackendGatewayOptions {
|
|
|
622
629
|
}
|
|
623
630
|
declare function runtimeBackendGateway(app: FastifyInstance, opts: RuntimeBackendGatewayOptions): Promise<void>;
|
|
624
631
|
|
|
625
|
-
export { type BeginIdempotencyOptions, BoringPluginAssetManager, BoringPluginEvent, BoringPluginFrontTarget, BoringPluginFrontTargetResolver, BoringPluginListEntry, type BoringPluginScanResult, BoringPluginSource, BoringPluginSourceInput, BoringServerPluginManifest, BridgeAuthContext, BridgeAuthPolicy, BridgeCallerClass, BridgeIdempotencyPolicy, type CompleteIdempotencyOptions, DEFAULT_WORKSPACE_BRIDGE_RUNTIME_REFRESH_TOKEN_TTL_MS, DEFAULT_WORKSPACE_BRIDGE_RUNTIME_TOKEN_TTL_MS, type IdempotencyBeginResult, type IdempotencyRecordStatus, InMemoryWorkspaceBridgeIdempotencyStore, InMemoryWorkspaceBridgeRuntimeRefreshTokenStore, MAX_WORKSPACE_BRIDGE_RUNTIME_TOKEN_TTL_MS, type MintWorkspaceBridgeRuntimeRefreshTokenOptions, type MintWorkspaceBridgeRuntimeTokenOptions, type PluginRestartWarning, type RuntimeBackendDiagnostic, type RuntimeBackendDispatchRequest, type RuntimeBackendDispatchResponse, type RuntimeBackendDispatcher, RuntimeBackendError, type RuntimeBackendGatewayOptions, RuntimeBackendRegistry, type RuntimeBackendReloadResult, type TrustedDomainBridgeHandlerOptions, type TrustedDomainBridgeHandlerPolicy, type TrustedDomainBridgeHandlerRegistration, UiBridge, type UiRoutesOptions, type VerifiedWorkspaceBridgeRuntimeRefreshToken, type VerifiedWorkspaceBridgeRuntimeToken, type VerifyWorkspaceBridgeRuntimeRefreshTokenOptions, type VerifyWorkspaceBridgeRuntimeTokenOptions, WORKSPACE_BRIDGE_REFRESH_TOKEN_AUDIENCE, WORKSPACE_BRIDGE_TOKEN_AUDIENCE, WorkspaceBridge, WorkspaceBridgeCallRequest, WorkspaceBridgeCallResponse, WorkspaceBridgeError, WorkspaceBridgeHandler, type WorkspaceBridgeHttpRoutesOptions, type WorkspaceBridgeIdempotencyRecord, type WorkspaceBridgeIdempotencyStore, WorkspaceBridgeOperationDefinition, WorkspaceBridgeRegistry, type WorkspaceBridgeRuntimeCore, type WorkspaceBridgeRuntimeCoreOptions, type WorkspaceBridgeRuntimeRefreshTokenClaims, type WorkspaceBridgeRuntimeRefreshTokenStore, type WorkspaceBridgeRuntimeRefreshTokenUseOptions, type WorkspaceBridgeRuntimeRefreshTokenUseResult, type WorkspaceBridgeRuntimeTokenClaims, WorkspaceServerPluginAsset, aggregatePluginPrompts, boringPluginRoutes, buildBoringSystemPrompt, clampWorkspaceBridgeRuntimeTokenTtlMs, collectRestartWarnings, createExecUiTool, createGetUiStateTool, createWorkspaceBridgeRuntimeCore, createWorkspaceUiTools, definePluginAsset, defineTrustedDomainBridgeHandler, hashNormalizedInput, mintWorkspaceBridgeRuntimeRefreshToken, mintWorkspaceBridgeRuntimeToken, pluginFileSignature, preflightBoringPlugins, readBoringPlugins, readPluginSignatureCache, resolvePluginAssetPath, runWithWorkspaceBridgeIdempotency, runtimeBackendGateway, runtimeClaimsToBridgeAuthContext, scanBoringPlugins, stableStringify, uiRoutes, verifyWorkspaceBridgeRuntimeRefreshToken, verifyWorkspaceBridgeRuntimeToken, workspaceBridgeHttpRoutes, writePluginSignatureCache };
|
|
632
|
+
export { type BeginIdempotencyOptions, BoringPluginAssetManager, BoringPluginEvent, BoringPluginFrontTarget, BoringPluginFrontTargetResolver, BoringPluginListEntry, type BoringPluginScanResult, BoringPluginSource, BoringPluginSourceInput, BoringServerPluginManifest, BridgeAuthContext, BridgeAuthPolicy, BridgeCallerClass, BridgeIdempotencyPolicy, type CompleteIdempotencyOptions, DEFAULT_WORKSPACE_BRIDGE_RUNTIME_REFRESH_TOKEN_TTL_MS, DEFAULT_WORKSPACE_BRIDGE_RUNTIME_TOKEN_TTL_MS, type IdempotencyBeginResult, type IdempotencyRecordStatus, InMemoryWorkspaceBridgeIdempotencyStore, InMemoryWorkspaceBridgeRuntimeRefreshTokenStore, MAX_WORKSPACE_BRIDGE_RUNTIME_TOKEN_TTL_MS, type MintWorkspaceBridgeRuntimeRefreshTokenOptions, type MintWorkspaceBridgeRuntimeTokenOptions, type PluginRestartWarning, type RuntimeBackendDiagnostic, type RuntimeBackendDispatchRequest, type RuntimeBackendDispatchResponse, type RuntimeBackendDispatcher, RuntimeBackendError, type RuntimeBackendGatewayOptions, RuntimeBackendRegistry, type RuntimeBackendReloadResult, type TrustedDomainBridgeHandlerOptions, type TrustedDomainBridgeHandlerPolicy, type TrustedDomainBridgeHandlerRegistration, UiBridge, type UiRoutesOptions, type VerifiedWorkspaceBridgeRuntimeRefreshToken, type VerifiedWorkspaceBridgeRuntimeToken, type VerifiedWorkspaceBridgeRuntimeTokenClaims, type VerifyWorkspaceBridgeRuntimeRefreshTokenOptions, type VerifyWorkspaceBridgeRuntimeTokenClaimsOptions, type VerifyWorkspaceBridgeRuntimeTokenOptions, WORKSPACE_BRIDGE_REFRESH_TOKEN_AUDIENCE, WORKSPACE_BRIDGE_TOKEN_AUDIENCE, WorkspaceBridge, WorkspaceBridgeCallRequest, WorkspaceBridgeCallResponse, WorkspaceBridgeError, WorkspaceBridgeHandler, type WorkspaceBridgeHttpRoutesOptions, type WorkspaceBridgeIdempotencyRecord, type WorkspaceBridgeIdempotencyStore, WorkspaceBridgeOperationDefinition, WorkspaceBridgeRegistry, type WorkspaceBridgeRuntimeCore, type WorkspaceBridgeRuntimeCoreOptions, type WorkspaceBridgeRuntimeRefreshTokenClaims, type WorkspaceBridgeRuntimeRefreshTokenStore, type WorkspaceBridgeRuntimeRefreshTokenUseOptions, type WorkspaceBridgeRuntimeRefreshTokenUseResult, type WorkspaceBridgeRuntimeTokenClaims, WorkspaceServerPluginAsset, aggregatePluginPrompts, authorizeWorkspaceBridgeRuntimeToken, boringPluginRoutes, buildBoringSystemPrompt, clampWorkspaceBridgeRuntimeTokenTtlMs, collectRestartWarnings, createExecUiTool, createGetUiStateTool, createWorkspaceBridgeRuntimeCore, createWorkspaceUiTools, definePluginAsset, defineTrustedDomainBridgeHandler, hashNormalizedInput, mintWorkspaceBridgeRuntimeRefreshToken, mintWorkspaceBridgeRuntimeToken, pluginFileSignature, preflightBoringPlugins, readBoringPlugins, readPluginSignatureCache, resolvePluginAssetPath, runWithWorkspaceBridgeIdempotency, runtimeBackendGateway, runtimeClaimsToBridgeAuthContext, scanBoringPlugins, stableStringify, uiRoutes, verifyWorkspaceBridgeRuntimeRefreshToken, verifyWorkspaceBridgeRuntimeToken, verifyWorkspaceBridgeRuntimeTokenClaims, workspaceBridgeHttpRoutes, writePluginSignatureCache };
|
package/dist/server.js
CHANGED
|
@@ -1409,20 +1409,28 @@ function mintWorkspaceBridgeRuntimeRefreshToken(options) {
|
|
|
1409
1409
|
});
|
|
1410
1410
|
}
|
|
1411
1411
|
function verifyWorkspaceBridgeRuntimeToken(token, options) {
|
|
1412
|
+
return authorizeWorkspaceBridgeRuntimeToken(
|
|
1413
|
+
verifyWorkspaceBridgeRuntimeTokenClaims(token, options),
|
|
1414
|
+
options.requiredCapabilities
|
|
1415
|
+
);
|
|
1416
|
+
}
|
|
1417
|
+
function verifyWorkspaceBridgeRuntimeTokenClaims(token, options) {
|
|
1412
1418
|
assertUsableSecret(options.secret);
|
|
1413
1419
|
const claims = parseAndVerifyToken(token, options.secret);
|
|
1414
1420
|
const now = Math.floor((options.nowMs ?? Date.now()) / 1e3);
|
|
1415
1421
|
ensureLiveTokenClaims(claims, now, WORKSPACE_BRIDGE_TOKEN_AUDIENCE, "Runtime bridge token");
|
|
1416
|
-
|
|
1417
|
-
|
|
1422
|
+
return { claims };
|
|
1423
|
+
}
|
|
1424
|
+
function authorizeWorkspaceBridgeRuntimeToken(verified, requiredCapabilities = []) {
|
|
1425
|
+
const missingCapability = requiredCapabilities.find(
|
|
1426
|
+
(capability) => !verified.claims.capabilities.includes(capability)
|
|
1418
1427
|
);
|
|
1419
1428
|
if (missingCapability) {
|
|
1420
1429
|
throw bridgeTokenError("BRIDGE_CAPABILITY_DENIED" /* CapabilityDenied */, "Runtime bridge token is missing a required capability");
|
|
1421
1430
|
}
|
|
1422
|
-
const runtimeClaims = claims;
|
|
1423
1431
|
return {
|
|
1424
|
-
claims:
|
|
1425
|
-
authContext: runtimeClaimsToBridgeAuthContext(
|
|
1432
|
+
claims: verified.claims,
|
|
1433
|
+
authContext: runtimeClaimsToBridgeAuthContext(verified.claims)
|
|
1426
1434
|
};
|
|
1427
1435
|
}
|
|
1428
1436
|
function verifyWorkspaceBridgeRuntimeRefreshToken(token, options) {
|
|
@@ -1644,14 +1652,25 @@ function workspaceBridgeHttpRoutes(app, opts, done) {
|
|
|
1644
1652
|
return sendBridgeError(reply, 400, void 0, "BRIDGE_SCHEMA_INVALID" /* SchemaInvalid */, "WorkspaceBridge request body is invalid");
|
|
1645
1653
|
}
|
|
1646
1654
|
const body = { ...parsed.data, input: parsed.data.input ?? {} };
|
|
1655
|
+
const authHeader = firstHeader2(request.headers.authorization);
|
|
1656
|
+
const runtimeToken = authHeader?.startsWith("Bearer ") ? authHeader.slice("Bearer ".length) : void 0;
|
|
1657
|
+
let verifiedRuntimeToken;
|
|
1658
|
+
if (runtimeToken !== void 0 && opts.assertRuntimeWorkspaceScope) {
|
|
1659
|
+
try {
|
|
1660
|
+
verifiedRuntimeToken = resolveRuntimeClaims(runtimeToken, opts);
|
|
1661
|
+
} catch (err) {
|
|
1662
|
+
const bridgeError = isBridgeError(err) ? err : createWorkspaceBridgeError("BRIDGE_HANDLER_FAILED" /* HandlerFailed */, "WorkspaceBridge transport failed");
|
|
1663
|
+
return sendBridgeError(reply, statusForBridgeError(bridgeError.code), body.requestId, bridgeError.code, bridgeError.message);
|
|
1664
|
+
}
|
|
1665
|
+
await opts.assertRuntimeWorkspaceScope(request, verifiedRuntimeToken.claims);
|
|
1666
|
+
}
|
|
1647
1667
|
try {
|
|
1648
1668
|
const registry = await resolveRegistry(request, body, opts);
|
|
1649
1669
|
const definition = registry.getDefinition(body.op);
|
|
1650
1670
|
if (!definition) {
|
|
1651
1671
|
return sendBridgeError(reply, statusForBridgeError("BRIDGE_OP_NOT_FOUND" /* OpNotFound */), body.requestId, "BRIDGE_OP_NOT_FOUND" /* OpNotFound */, "WorkspaceBridge operation is not registered");
|
|
1652
1672
|
}
|
|
1653
|
-
const
|
|
1654
|
-
const authContext = authHeader?.startsWith("Bearer ") ? resolveRuntimeContext(authHeader.slice("Bearer ".length), opts, definition) : await resolveBrowserContext(request, opts, definition, body);
|
|
1673
|
+
const authContext = runtimeToken !== void 0 ? resolveRuntimeContext(runtimeToken, opts, definition, verifiedRuntimeToken) : await resolveBrowserContext(request, opts, definition, body);
|
|
1655
1674
|
const idempotencyStore = opts.getIdempotencyStore ? await opts.getIdempotencyStore(request, body) : opts.idempotencyStore;
|
|
1656
1675
|
const expectedWorkspaceId = opts.getOwnerWorkspaceId ? await opts.getOwnerWorkspaceId(request, body, authContext) : opts.ownerWorkspaceId;
|
|
1657
1676
|
const response = await runWithWorkspaceBridgeIdempotency(idempotencyStore, {
|
|
@@ -1674,12 +1693,21 @@ function workspaceBridgeHttpRoutes(app, opts, done) {
|
|
|
1674
1693
|
if (!opts.runtimeTokenSecret || !opts.runtimeRefreshTokenSecret) {
|
|
1675
1694
|
return sendBridgeError(reply, 401, void 0, "BRIDGE_AUTH_REQUIRED" /* AuthRequired */, "WorkspaceBridge token refresh is not configured");
|
|
1676
1695
|
}
|
|
1696
|
+
const nowMs = Date.now();
|
|
1697
|
+
let verified;
|
|
1677
1698
|
try {
|
|
1678
|
-
|
|
1679
|
-
const verified = verifyWorkspaceBridgeRuntimeRefreshToken(authHeader.slice("Bearer ".length), {
|
|
1699
|
+
verified = verifyWorkspaceBridgeRuntimeRefreshToken(authHeader.slice("Bearer ".length), {
|
|
1680
1700
|
secret: opts.runtimeRefreshTokenSecret,
|
|
1681
1701
|
nowMs
|
|
1682
1702
|
});
|
|
1703
|
+
} catch (err) {
|
|
1704
|
+
const bridgeError = isBridgeError(err) ? err : createWorkspaceBridgeError("BRIDGE_INVALID_TOKEN" /* InvalidToken */, "WorkspaceBridge refresh token is invalid");
|
|
1705
|
+
return sendBridgeError(reply, statusForBridgeError(bridgeError.code), void 0, bridgeError.code, bridgeError.message);
|
|
1706
|
+
}
|
|
1707
|
+
if (opts.assertRuntimeWorkspaceScope) {
|
|
1708
|
+
await opts.assertRuntimeWorkspaceScope(request, verified.claims);
|
|
1709
|
+
}
|
|
1710
|
+
try {
|
|
1683
1711
|
const store = opts.getRuntimeRefreshTokenStore ? await opts.getRuntimeRefreshTokenStore(request, verified.claims) ?? defaultRefreshTokenStore : defaultRefreshTokenStore;
|
|
1684
1712
|
const refreshUse = await store.recordUse({
|
|
1685
1713
|
jti: verified.claims.jti,
|
|
@@ -1722,7 +1750,10 @@ async function resolveRegistry(request, body, opts) {
|
|
|
1722
1750
|
}
|
|
1723
1751
|
return registry;
|
|
1724
1752
|
}
|
|
1725
|
-
function resolveRuntimeContext(token, opts, definition) {
|
|
1753
|
+
function resolveRuntimeContext(token, opts, definition, verified) {
|
|
1754
|
+
if (verified) {
|
|
1755
|
+
return authorizeWorkspaceBridgeRuntimeToken(verified, definition.requiredCapabilities).authContext;
|
|
1756
|
+
}
|
|
1726
1757
|
if (!opts.runtimeTokenSecret) {
|
|
1727
1758
|
throw createWorkspaceBridgeError("BRIDGE_AUTH_REQUIRED" /* AuthRequired */, "Runtime bridge token auth is not configured");
|
|
1728
1759
|
}
|
|
@@ -1731,6 +1762,12 @@ function resolveRuntimeContext(token, opts, definition) {
|
|
|
1731
1762
|
requiredCapabilities: definition.requiredCapabilities
|
|
1732
1763
|
}).authContext;
|
|
1733
1764
|
}
|
|
1765
|
+
function resolveRuntimeClaims(token, opts) {
|
|
1766
|
+
if (!opts.runtimeTokenSecret) {
|
|
1767
|
+
throw createWorkspaceBridgeError("BRIDGE_AUTH_REQUIRED" /* AuthRequired */, "Runtime bridge token auth is not configured");
|
|
1768
|
+
}
|
|
1769
|
+
return verifyWorkspaceBridgeRuntimeTokenClaims(token, { secret: opts.runtimeTokenSecret });
|
|
1770
|
+
}
|
|
1734
1771
|
async function resolveBrowserContext(request, opts, definition, body) {
|
|
1735
1772
|
if (!opts.browserAuthPolicy) {
|
|
1736
1773
|
throw createWorkspaceBridgeError("BRIDGE_AUTH_REQUIRED" /* AuthRequired */, "Browser bridge auth is not configured");
|
|
@@ -3800,6 +3837,7 @@ export {
|
|
|
3800
3837
|
WorkspaceBridgeErrorCode,
|
|
3801
3838
|
WorkspaceBridgeRegistry,
|
|
3802
3839
|
aggregatePluginPrompts,
|
|
3840
|
+
authorizeWorkspaceBridgeRuntimeToken,
|
|
3803
3841
|
bootstrapServer,
|
|
3804
3842
|
boringPluginRoutes,
|
|
3805
3843
|
buildBoringSystemPrompt,
|
|
@@ -3840,6 +3878,7 @@ export {
|
|
|
3840
3878
|
validateWorkspaceBridgeOperationDefinition,
|
|
3841
3879
|
verifyWorkspaceBridgeRuntimeRefreshToken,
|
|
3842
3880
|
verifyWorkspaceBridgeRuntimeToken,
|
|
3881
|
+
verifyWorkspaceBridgeRuntimeTokenClaims,
|
|
3843
3882
|
workspaceBridgeHttpRoutes,
|
|
3844
3883
|
writePluginSignatureCache
|
|
3845
3884
|
};
|
package/dist/workspace.css
CHANGED
|
@@ -6028,7 +6028,6 @@
|
|
|
6028
6028
|
--tracking-widest: 0.1em;
|
|
6029
6029
|
--leading-snug: 1.375;
|
|
6030
6030
|
--radius-xs: 0.125rem;
|
|
6031
|
-
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
6032
6031
|
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
|
6033
6032
|
--animate-spin: spin 1s linear infinite;
|
|
6034
6033
|
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
@@ -6172,6 +6171,9 @@
|
|
|
6172
6171
|
.grid {
|
|
6173
6172
|
display: grid;
|
|
6174
6173
|
}
|
|
6174
|
+
.inline {
|
|
6175
|
+
display: inline;
|
|
6176
|
+
}
|
|
6175
6177
|
.inline-block {
|
|
6176
6178
|
display: inline-block;
|
|
6177
6179
|
}
|
|
@@ -6714,9 +6716,6 @@
|
|
|
6714
6716
|
.bg-\[color\:var\(--boring-success-soft\,var\(--secondary\)\)\] {
|
|
6715
6717
|
background-color: var(--boring-success-soft,var(--secondary));
|
|
6716
6718
|
}
|
|
6717
|
-
.bg-\[color\:var\(--boring-warning\,var\(--accent-foreground\)\)\] {
|
|
6718
|
-
background-color: var(--boring-warning,var(--accent-foreground));
|
|
6719
|
-
}
|
|
6720
6719
|
.bg-\[color\:var\(--boring-warning-soft\,var\(--accent\)\)\] {
|
|
6721
6720
|
background-color: var(--boring-warning-soft,var(--accent));
|
|
6722
6721
|
}
|
|
@@ -7134,11 +7133,6 @@
|
|
|
7134
7133
|
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
|
7135
7134
|
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
|
7136
7135
|
}
|
|
7137
|
-
.transition-\[width\] {
|
|
7138
|
-
transition-property: width;
|
|
7139
|
-
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
|
7140
|
-
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
|
7141
|
-
}
|
|
7142
7136
|
.transition-all {
|
|
7143
7137
|
transition-property: all;
|
|
7144
7138
|
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
|
@@ -7175,18 +7169,10 @@
|
|
|
7175
7169
|
--tw-duration: 200ms;
|
|
7176
7170
|
transition-duration: 200ms;
|
|
7177
7171
|
}
|
|
7178
|
-
.duration-300 {
|
|
7179
|
-
--tw-duration: 300ms;
|
|
7180
|
-
transition-duration: 300ms;
|
|
7181
|
-
}
|
|
7182
7172
|
.ease-in-out {
|
|
7183
7173
|
--tw-ease: var(--ease-in-out);
|
|
7184
7174
|
transition-timing-function: var(--ease-in-out);
|
|
7185
7175
|
}
|
|
7186
|
-
.ease-out {
|
|
7187
|
-
--tw-ease: var(--ease-out);
|
|
7188
|
-
transition-timing-function: var(--ease-out);
|
|
7189
|
-
}
|
|
7190
7176
|
.outline-none {
|
|
7191
7177
|
--tw-outline-style: none;
|
|
7192
7178
|
outline-style: none;
|
|
@@ -8444,6 +8430,64 @@
|
|
|
8444
8430
|
height: calc(var(--spacing) * 4);
|
|
8445
8431
|
}
|
|
8446
8432
|
}
|
|
8433
|
+
.\[\&\:\:-moz-progress-bar\]\:rounded-full {
|
|
8434
|
+
&::-moz-progress-bar {
|
|
8435
|
+
border-radius: calc(infinity * 1px);
|
|
8436
|
+
}
|
|
8437
|
+
}
|
|
8438
|
+
.\[\&\:\:-moz-progress-bar\]\:bg-\[color\:var\(--boring-warning\,var\(--accent-foreground\)\)\] {
|
|
8439
|
+
&::-moz-progress-bar {
|
|
8440
|
+
background-color: var(--boring-warning,var(--accent-foreground));
|
|
8441
|
+
}
|
|
8442
|
+
}
|
|
8443
|
+
.\[\&\:\:-moz-progress-bar\]\:bg-destructive {
|
|
8444
|
+
&::-moz-progress-bar {
|
|
8445
|
+
background-color: var(--boring-destructive);
|
|
8446
|
+
}
|
|
8447
|
+
}
|
|
8448
|
+
.\[\&\:\:-moz-progress-bar\]\:bg-primary {
|
|
8449
|
+
&::-moz-progress-bar {
|
|
8450
|
+
background-color: var(--boring-primary);
|
|
8451
|
+
}
|
|
8452
|
+
}
|
|
8453
|
+
.\[\&\:\:-webkit-progress-bar\]\:bg-muted {
|
|
8454
|
+
&::-webkit-progress-bar {
|
|
8455
|
+
background-color: var(--boring-muted);
|
|
8456
|
+
}
|
|
8457
|
+
}
|
|
8458
|
+
.\[\&\:\:-webkit-progress-value\]\:rounded-full {
|
|
8459
|
+
&::-webkit-progress-value {
|
|
8460
|
+
border-radius: calc(infinity * 1px);
|
|
8461
|
+
}
|
|
8462
|
+
}
|
|
8463
|
+
.\[\&\:\:-webkit-progress-value\]\:bg-\[color\:var\(--boring-warning\,var\(--accent-foreground\)\)\] {
|
|
8464
|
+
&::-webkit-progress-value {
|
|
8465
|
+
background-color: var(--boring-warning,var(--accent-foreground));
|
|
8466
|
+
}
|
|
8467
|
+
}
|
|
8468
|
+
.\[\&\:\:-webkit-progress-value\]\:bg-destructive {
|
|
8469
|
+
&::-webkit-progress-value {
|
|
8470
|
+
background-color: var(--boring-destructive);
|
|
8471
|
+
}
|
|
8472
|
+
}
|
|
8473
|
+
.\[\&\:\:-webkit-progress-value\]\:bg-primary {
|
|
8474
|
+
&::-webkit-progress-value {
|
|
8475
|
+
background-color: var(--boring-primary);
|
|
8476
|
+
}
|
|
8477
|
+
}
|
|
8478
|
+
.\[\&\:\:-webkit-progress-value\]\:transition-all {
|
|
8479
|
+
&::-webkit-progress-value {
|
|
8480
|
+
transition-property: all;
|
|
8481
|
+
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
|
|
8482
|
+
transition-duration: var(--tw-duration, var(--default-transition-duration));
|
|
8483
|
+
}
|
|
8484
|
+
}
|
|
8485
|
+
.\[\&\:\:-webkit-progress-value\]\:duration-300 {
|
|
8486
|
+
&::-webkit-progress-value {
|
|
8487
|
+
--tw-duration: 300ms;
|
|
8488
|
+
transition-duration: 300ms;
|
|
8489
|
+
}
|
|
8490
|
+
}
|
|
8447
8491
|
.\[\&\:\:-webkit-scrollbar\]\:hidden {
|
|
8448
8492
|
&::-webkit-scrollbar {
|
|
8449
8493
|
display: none;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hachej/boring-workspace",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.83",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Workspace UI, plugin, and bridge package for composing chat, files, catalogs, editors, and app-specific panes.",
|
|
@@ -139,9 +139,9 @@
|
|
|
139
139
|
"tailwind-merge": "^2.0.0",
|
|
140
140
|
"zod": "^3.23.0",
|
|
141
141
|
"zustand": "^5.0.14",
|
|
142
|
-
"@hachej/boring-agent": "0.1.
|
|
143
|
-
"@hachej/boring-ui-
|
|
144
|
-
"@hachej/boring-ui-
|
|
142
|
+
"@hachej/boring-agent": "0.1.83",
|
|
143
|
+
"@hachej/boring-ui-kit": "0.1.83",
|
|
144
|
+
"@hachej/boring-ui-plugin-cli": "0.1.83"
|
|
145
145
|
},
|
|
146
146
|
"devDependencies": {
|
|
147
147
|
"@tailwindcss/postcss": "^4.3.1",
|