Repository navigation
feat(appkit): surface caller expiry and support local OBO - #597
Conversation
📦 Bundle size reportCompared against
|
| dist | raw | gzip |
|---|---|---|
| JS (runtime) | 1.2 MB (+25 KB) | 437 KB (+9.3 KB) |
| Type declarations | 452 KB (+6.4 KB) | 164 KB (+2.4 KB) |
| Source maps | 2.4 MB (+45 KB) | 819 KB (+17 KB) |
| Other | 11 KB | 3.7 KB |
| Total | 4.1 MB (+76 KB) | 1.4 MB (+29 KB) |
Per-entry composition (own code — deps external (as shipped))
| Entry | Initial (gz) | Lazy (gz) | Total (gz) | node_modules (min) | Own code (min) |
|---|---|---|---|---|---|
. |
99 KB (+3.1 KB) | 2.5 KB (-1 B) | 102 KB (+3.1 KB) | external | 325 KB (+9.6 KB) |
./beta |
95 KB (+1.6 KB) | 463 B (-15 B) | 96 KB (+1.6 KB) | external | 288 KB (+5.2 KB) |
./testing |
41 KB (+2.2 KB) | 32 KB (+1.0 KB) | 73 KB (+3.2 KB) | external | 210 KB (+8.2 KB) |
./tsdown |
520 B | 0 B | 520 B | external | 813 B |
./type-generator |
23 KB | 0 B | 23 KB | external | 65 KB |
Chunks:
| Entry | Chunk | Load | Size (gz) |
|---|---|---|---|
. |
index.js |
initial | 95 KB |
. |
utils.js |
initial | 4.6 KB |
. |
remote-tunnel-manager.js |
lazy | 2.5 KB |
./beta |
beta.js |
initial | 78 KB |
./beta |
stream-manager.js |
initial | 5.9 KB |
./beta |
service-context.js |
initial | 4.1 KB |
./beta |
databricks.js |
initial | 3.3 KB |
./beta |
wide-event-emitter.js |
initial | 3.2 KB |
./beta |
client.js |
initial | 594 B |
./beta |
index.js |
initial | 20 B |
./beta |
supervisor-api.js |
lazy | 193 B |
./beta |
databricks.js |
lazy | 155 B |
./beta |
index.js |
lazy | 115 B |
./testing |
manifest.js |
initial | 27 KB |
./testing |
index.js |
initial | 10 KB |
./testing |
wide-event-emitter.js |
initial | 2.9 KB |
./testing |
index.js |
lazy | 28 KB |
./testing |
remote-tunnel-manager.js |
lazy | 2.5 KB |
./testing |
utils.js |
lazy | 1.8 KB |
./tsdown |
index.js |
initial | 520 B |
./type-generator |
index.js |
initial | 23 KB |
@databricks/appkit-ui
npm tarball (packed): 350 KB (+4 B) — gzipped download (dist + bin; excludes release-only docs/NOTICE).
| dist | raw | gzip |
|---|---|---|
| JS (runtime) | 395 KB | 132 KB |
| Type declarations | 229 KB | 84 KB (+1 B) |
| Source maps | 766 KB | 253 KB (+1 B) |
| CSS | 16 KB | 3.2 KB |
| Total | 1.4 MB | 472 KB (+2 B) |
Per-entry composition (consumer bundle — deps bundled, peerDeps external)
| Entry | Initial (gz) | Lazy (gz) | Total (gz) | node_modules (min) | Own code (min) |
|---|---|---|---|---|---|
./js |
5.3 KB | 49 KB | 55 KB | 208 KB | 14 KB |
./js/beta |
20 B | 0 B | 20 B | 0 B | 0 B |
./react |
432 KB | 49 KB | 481 KB | 1.3 MB | 177 KB |
./react/beta |
1.0 KB | 0 B | 1.0 KB | 0 B | 1.9 KB |
Chunks:
| Entry | Chunk | Load | Size (gz) |
|---|---|---|---|
./js |
index.js |
initial | 5.2 KB |
./js |
chunk |
initial | 120 B |
./js |
apache-arrow |
lazy | 49 KB |
./js/beta |
beta.js |
initial | 20 B |
./react |
index.js |
initial | 430 KB |
./react |
tslib |
initial | 2.1 KB |
./react |
apache-arrow |
lazy | 49 KB |
./react/beta |
beta.js |
initial | 1.0 KB |
🤖 AppKit PR bot🔬 Run evalsStart an eval for this PR from the evals-monitor app: Go to Evals Monitor → 📦 Try this PR's app templateScaffolds a new app from this PR's SDK build. Run it in any folder (requires the GitHub CLI — gh run download 37492789246 -R databricks/appkit -n appkit-template-0.82.0-pr.889ede7-execution-identity-lifecycle-597 -D appkit-pr-597 \
&& unzip -o "appkit-pr-597/appkit-template-0.82.0-pr.889ede7-execution-identity-lifecycle-597.zip" -d "appkit-pr-597" \
&& databricks apps init --template "appkit-pr-597"The template pins |
2790860 to
25ecd06
Compare
45d2d28 to
81ff9a7
Compare
e0c118d to
d9da769
Compare
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Use plain punctuation in the inherited error comment so generated pages follow repository style. Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
d9da769 to
4b22685
Compare
Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Resolves the agents.ts imports: keeps this branch's normalizeIdentityError and drops createRequestScope, which the routes no longer use now that user scope applies per plugin tool call. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
The identity-expiration route test made the model call fail with a 401. The model call now runs as the app service principal, so its failure is not a user identity expiry. The test now fails a plugin tool call, which runs in user scope, and still checks that both agent routes return IDENTITY_EXPIRED without leaking the token. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
The packaged-CLI import guard is useful but unrelated to local OBO, so it moves to its own PR off main. Remove it here: the validate-package-imports script and its test, the root knip entry, the root @ast-grep/napi devDependency, and the dist-appkit import and call. dist-appkit.ts now matches main again; the dev-obo move needed no change to its copy logic. The appkit and shared @ast-grep/napi dependencies are unchanged. Running the guard against this branch's packed CLI before the removal found no missing relative imports. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
atilafassina
left a comment
There was a problem hiding this comment.
Can be done in a separate PR.
I think Analytics swallows the IdentityError before hitting the normalization path, so identity issues in queries will surface as ExecutionError / generic 500s instead of 401s
snippet from warehouse connector:
/**
* Normalize an error caught during statement execution/polling and rethrow.
* Abort and already-structured `AppKitError`s pass through untouched;
* anything else is wrapped as an `ExecutionError`, preserving the SDK's
* structured `ApiError.errorCode` (e.g. "INVALID_PARAMETER_VALUE",
* "BAD_REQUEST") so callers can branch on a stable identifier rather than
* substring-matching the message.
*/
private _rethrowStatementError(error: unknown): never {
if (error instanceof Error && error.name === "AbortError") {
throw error;
}
if (error instanceof AppKitError) {
throw error;
}
const sdkErrorCode =
error && typeof error === "object" && "errorCode" in error
? (error as { errorCode?: unknown }).errorCode
: undefined;
throw ExecutionError.statementFailed(
error instanceof Error ? error.message : String(error),
typeof sdkErrorCode === "string" ? sdkErrorCode : undefined,
);
}We could quickly add an extra check here for now, but probably a good follow-up is to have different heuristics for Analytics to surface errors.
…cycle Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Summary
Caller operations expose downstream credential rejection as
IdentityExpiredError(IDENTITY_EXPIRED), and local apps can exercise real user execution through the normalnpm run devworkflow.This is layer 4 of the stack, based on #595 (
execution-standalone-user). Design:design-docs/execution-identity-e2e.md, section 5.1.4. Cache partitioning is in #594.appkit.execution.principal,appkit.execution.principal_id, and the initiating user'sappkit.execution.actor_idwhen present. Tokens are never span attributes.DATABRICKS_TOKENwithDATABRICKS_HOSTfirst, otherwise the explicitly configuredDATABRICKS_CONFIG_PROFILE. No separate proxy command, target, or port is needed.APPKIT_DEV_OBO=false.asUser(req)selects user execution; unscoped calls keep the app's configured credentials. SP remains the ordinary default, group is deferred, and the markedDEV_OBO_FALLBACKremains when injection is disabled or unconfigured.Local emulation supplies user credentials; it does not emulate platform consent, scope enforcement, or resource provisioning. A real SP-versus-user comparison requires the app's default credentials to belong to an SP.
Compatibility
Plugin
execute()preserves its existing failed-result envelope and adds an optional typederrorfield. Throwing APIs exposeIdentityExpiredError, and HTTP/SSE agent responses carry its stable code. The error retains only a token fingerprint, not credential-bearing upstream errors. Non-401 failures and SP execution retain their existing behavior. Existing public compatibility aliases remain available.Verification
pnpm -r typecheck, full monorepo unit suite: 5,301 passed, one existing skip.pnpm build,pnpm docs:build, formatting/lint, and Knip.--helpsmoke check.