@happyvertical/smrt-users 0.51.36 → 0.51.39
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/AGENTS.md +1 -0
- package/agents/mobile-auth.md +45 -0
- package/agents/oidc-provisioning.md +97 -0
- package/agents/permissions.md +186 -0
- package/agents/retention.md +52 -0
- package/agents/terminal-auth-testing.md +32 -0
- package/dist/chunks/{TerminalAuthService-D9OXHSHy.js → TerminalAuthService-BDKUbg4N.js} +4 -3
- package/dist/chunks/TerminalAuthService-BDKUbg4N.js.map +1 -0
- package/dist/collections/CliAuthApproveLimitCollection.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/manifest.json +1 -1
- package/dist/smrt-knowledge.json +11 -5
- package/dist/sveltekit.js +1 -1
- package/package.json +11 -10
- package/dist/chunks/TerminalAuthService-D9OXHSHy.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CliAuthApproveLimitCollection.d.ts","sourceRoot":"","sources":["../../src/collections/CliAuthApproveLimitCollection.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,MAAM,MAAM,yBAAyB,GACjC;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,qBAAa,kCAAmC,SAAQ,cAAc,CAAC,wBAAwB,CAAC;IAC9F,MAAM,CAAC,QAAQ,CAAC,UAAU,kCAA4B;IAEtD;;;OAGG;IACG,cAAc,CAAC,KAAK,EAAE;QAC1B,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"CliAuthApproveLimitCollection.d.ts","sourceRoot":"","sources":["../../src/collections/CliAuthApproveLimitCollection.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,MAAM,MAAM,yBAAyB,GACjC;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,qBAAa,kCAAmC,SAAQ,cAAc,CAAC,wBAAwB,CAAC;IAC9F,MAAM,CAAC,QAAQ,CAAC,UAAU,kCAA4B;IAEtD;;;OAGG;IACG,cAAc,CAAC,KAAK,EAAE;QAC1B,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAmEtC,+EAA+E;IACzE,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAoB7E"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as deriveOperationPermissionSlug, A as DEFAULT_ANCESTOR_READ_MAX_DEPTH, B as TenantPermissionOverride, C as OidcLoginService, Ct as UsersCliAuthRequestCollection, D as resolveOidcProviderConfig, Dt as generateSessionId, E as getUsersOidcConfig, Et as Session, F as UserCollection, G as applyTenantHierarchyUpdates, H as Tenant, J as recordTenantHierarchyChanges, K as assertTenantTableName, L as UserEmailKeyBackfillError, M as isAncestorReadableSlug, N as normalizeAncestorReadPolicy, Ot as UsersCliAuthRequest, P as OidcProvisioningError, Q as deriveOperationPermissionCollectionName, R as backfillUserEmailKeys, S as OidcLoginError, St as normalizeEmail, T as encodeOidcTransaction, Tt as DEFAULT_SESSION_TTL, U as MAX_TENANT_HIERARCHY_DEPTH, V as TenantCollection, W as TenantHierarchyError, X as RolePermissionCollection, Y as DEFAULT_ROLE_PERMISSION_PATTERNS, Z as PermissionCatalogService, _ as readMobileBearerToken, _t as Group, a as TerminalAuthRateLimitError, at as Role, b as PermissionResolver, bt as User, c as assertOperationPermission, ct as MembershipOverrideCollection, d as getCurrentSessionPermissionContext, dt as Membership, et as normalizeOperationPermissionAction, f as getRequestScopedDatabase, ft as GroupRoleCollection, g as MobileAuthService, gt as GroupCollection, h as MobileAuthError, ht as GroupMember, i as TerminalAuthError, it as RoleCollection, j as getConfiguredAncestorReadPolicy, k as ANCESTOR_READ_ACTION, l as checkOperationPermission, lt as MembershipOverride, m as withSessionPermissionContext, mt as GroupMemberCollection, n as DEFAULT_CLI_AUTH_REQUEST_TTL_SECONDS, nt as syncPermissionCatalog, o as TerminalAuthService, ot as PermissionCollection, p as withPrincipalPermissionContext, pt as GroupRole, q as planTenantHierarchy, r as DEFAULT_CLI_SESSION_TTL_SECONDS, rt as RolePermission, s as OperationPermissionError, st as Permission, t as DEFAULT_CLI_AUTH_POLL_INTERVAL_SECONDS, tt as registerPermissionDefinitions, u as hasOperationPermission, ut as MembershipCollection, v as validateMobileRedirectUri, vt as UsersCliAuthApproveLimitCollection, w as decodeOidcTransaction, wt as SessionCollection, x as withoutListBounds, xt as isValidEmail, y as SessionService, yt as UsersCliAuthApproveLimit, z as TenantPermissionOverrideCollection } from "./chunks/TerminalAuthService-
|
|
1
|
+
import { $ as deriveOperationPermissionSlug, A as DEFAULT_ANCESTOR_READ_MAX_DEPTH, B as TenantPermissionOverride, C as OidcLoginService, Ct as UsersCliAuthRequestCollection, D as resolveOidcProviderConfig, Dt as generateSessionId, E as getUsersOidcConfig, Et as Session, F as UserCollection, G as applyTenantHierarchyUpdates, H as Tenant, J as recordTenantHierarchyChanges, K as assertTenantTableName, L as UserEmailKeyBackfillError, M as isAncestorReadableSlug, N as normalizeAncestorReadPolicy, Ot as UsersCliAuthRequest, P as OidcProvisioningError, Q as deriveOperationPermissionCollectionName, R as backfillUserEmailKeys, S as OidcLoginError, St as normalizeEmail, T as encodeOidcTransaction, Tt as DEFAULT_SESSION_TTL, U as MAX_TENANT_HIERARCHY_DEPTH, V as TenantCollection, W as TenantHierarchyError, X as RolePermissionCollection, Y as DEFAULT_ROLE_PERMISSION_PATTERNS, Z as PermissionCatalogService, _ as readMobileBearerToken, _t as Group, a as TerminalAuthRateLimitError, at as Role, b as PermissionResolver, bt as User, c as assertOperationPermission, ct as MembershipOverrideCollection, d as getCurrentSessionPermissionContext, dt as Membership, et as normalizeOperationPermissionAction, f as getRequestScopedDatabase, ft as GroupRoleCollection, g as MobileAuthService, gt as GroupCollection, h as MobileAuthError, ht as GroupMember, i as TerminalAuthError, it as RoleCollection, j as getConfiguredAncestorReadPolicy, k as ANCESTOR_READ_ACTION, l as checkOperationPermission, lt as MembershipOverride, m as withSessionPermissionContext, mt as GroupMemberCollection, n as DEFAULT_CLI_AUTH_REQUEST_TTL_SECONDS, nt as syncPermissionCatalog, o as TerminalAuthService, ot as PermissionCollection, p as withPrincipalPermissionContext, pt as GroupRole, q as planTenantHierarchy, r as DEFAULT_CLI_SESSION_TTL_SECONDS, rt as RolePermission, s as OperationPermissionError, st as Permission, t as DEFAULT_CLI_AUTH_POLL_INTERVAL_SECONDS, tt as registerPermissionDefinitions, u as hasOperationPermission, ut as MembershipCollection, v as validateMobileRedirectUri, vt as UsersCliAuthApproveLimitCollection, w as decodeOidcTransaction, wt as SessionCollection, x as withoutListBounds, xt as isValidEmail, y as SessionService, yt as UsersCliAuthApproveLimit, z as TenantPermissionOverrideCollection } from "./chunks/TerminalAuthService-BDKUbg4N.js";
|
|
2
2
|
import { a as MembershipStatus, c as TenantPermissionEffect, i as DEFAULT_TENANT_POLICY, l as TenantStatus, n as DEFAULT_ROLES, o as OverrideEffect, r as DEFAULT_ROLE_SLUGS, s as SessionStatus, t as AccessRequestStatus, u as UserStatus } from "./chunks/types-DFqeph0R.js";
|
|
3
3
|
import { ObjectRegistry, SmrtCollection, SmrtObject, field, findManifestEntryByQualifiedName, foreignKey, isUniqueViolationError, registerRetentionTask, smrt, unregisterRetentionTask } from "@happyvertical/smrt-core";
|
|
4
4
|
import { PROFILE_EMAIL_KEY_BACKFILL_NAME, Person, ProfileCollection, ProfileTypeCollection, normalizeIdentityEmail } from "@happyvertical/smrt-profiles";
|
|
@@ -1194,7 +1194,7 @@ var MagicLinkService = class MagicLinkService {
|
|
|
1194
1194
|
* The caller is responsible for emailing the token to the user.
|
|
1195
1195
|
*/
|
|
1196
1196
|
async generate(email) {
|
|
1197
|
-
const { SignJWT } = await import("./chunks/TerminalAuthService-
|
|
1197
|
+
const { SignJWT } = await import("./chunks/TerminalAuthService-BDKUbg4N.js").then((n) => n.O);
|
|
1198
1198
|
const key = await this.getSigningKey();
|
|
1199
1199
|
const nonce = crypto.randomUUID();
|
|
1200
1200
|
const normalizedEmail = normalizeEmail(email);
|
|
@@ -1223,7 +1223,7 @@ var MagicLinkService = class MagicLinkService {
|
|
|
1223
1223
|
* @throws {MagicLinkError} If the token is invalid, expired, or already used
|
|
1224
1224
|
*/
|
|
1225
1225
|
async verify(token) {
|
|
1226
|
-
const { jwtVerify, errors } = await import("./chunks/TerminalAuthService-
|
|
1226
|
+
const { jwtVerify, errors } = await import("./chunks/TerminalAuthService-BDKUbg4N.js").then((n) => n.O);
|
|
1227
1227
|
const key = await this.getSigningKey();
|
|
1228
1228
|
let payload;
|
|
1229
1229
|
try {
|
package/dist/manifest.json
CHANGED
package/dist/smrt-knowledge.json
CHANGED
|
@@ -3,16 +3,17 @@
|
|
|
3
3
|
"sensitiveFieldsExcluded": true,
|
|
4
4
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
5
5
|
"packageName": "@happyvertical/smrt-users",
|
|
6
|
-
"packageVersion": "0.51.
|
|
6
|
+
"packageVersion": "0.51.39",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
12
|
-
"agents": "
|
|
10
|
+
"manifest": "19ba052694414c0a46e25dc2500c99a39886ac821a02b5ceb7ad5e900a528f1c",
|
|
11
|
+
"packageJson": "1a986f013f79d7f2bd0da8ea4d29d258a57489c8240695bf676b3b37bded4a13",
|
|
12
|
+
"agents": "c1bd1dcae5f1662f31d01d0cff19cb3f774715eb71ecfd249eb429e5f64a3eb7",
|
|
13
13
|
"moduleDoc:agents/permissions.md": "b5be3f5b84b409cb6e62080e2d7a75b67e0763266c11054045c5c401b84f8dd6",
|
|
14
14
|
"moduleDoc:agents/oidc-provisioning.md": "5efa607ff23b9a693391e0c02670324a8cea4114d4968c9718f10a763da919c6",
|
|
15
15
|
"moduleDoc:agents/mobile-auth.md": "25e85e83f43e3a46383a92fa809f3a003b4545c3026e78dbe1bccbbc35161e18",
|
|
16
|
+
"moduleDoc:agents/terminal-auth-testing.md": "8a84c16a19e381427aed81d3b1882344c427fe22a70e87f5ac2db836b1a6822d",
|
|
16
17
|
"moduleDoc:agents/retention.md": "425c0a34ed33969badfef699751bfa670bdf618eda65e079e00815620aabed68"
|
|
17
18
|
},
|
|
18
19
|
"exports": [
|
|
@@ -10555,7 +10556,7 @@
|
|
|
10555
10556
|
"polymorphicAssociations": 0,
|
|
10556
10557
|
"uuidColumns": 90
|
|
10557
10558
|
},
|
|
10558
|
-
"agentDoc": "# @happyvertical/smrt-users\n\nMulti-tenant identity, RBAC, hierarchical tenants, sessions, and SvelteKit auth.\n\n## Modules\n\nRead only the module relevant to the change; protocol and provisioning details\nare not prerequisites for unrelated user-package work.\n\n| Module | Scope | Module doc |\n|---|---|---|\n| `src/services/PermissionResolver.ts` | permission precedence, inherited memberships, guards, RLS, role seeding | [agents/permissions.md](agents/permissions.md) |\n| `src/services/OidcLoginService.ts`, collections and OIDC handlers | identity reconciliation, transaction boundaries, migration readiness | [agents/oidc-provisioning.md](agents/oidc-provisioning.md) |\n| `src/services/MobileAuthService.ts` | mobile handshake, bearer sessions, bootstrap extension boundary | [agents/mobile-auth.md](agents/mobile-auth.md) |\n| `src/retention.ts` | expired session/token/CLI-auth reaping and retention sweep wiring | [agents/retention.md](agents/retention.md) |\n\n## Models and authority\n\n- Users are global; tenant access comes through Membership (unique user/tenant).\n User email is normalized and globally unique through readonly nullable\n `emailKey`. `profileId` is a unique cross-package reference: at most one User\n owns each non-null Profile.\n- Tenant uses STI and a materialized hierarchy, maximum depth 10.\n `hierarchyPath`/`hierarchyLevel` are derived from `parentTenantId` by\n `Tenant.save()` on every save (any caller-supplied value is recomputed) and\n descendants are re-materialized when they change; never hand-maintain them.\n Legacy rows are backfilled with `smrt db:materialize-tenant-hierarchy`\n (`materializeTenantHierarchy()`). Tests that need a corrupt path must write it\n with raw SQL (#3036).\n- Role with `tenantId = null` is available to all tenants; `isSystem` prevents\n deletion. `inheritsToDescendants` is opt-in. Seed owner/admin/member/viewer\n through `RoleCollection.seedSystemRoles()` at application initialization.\n- Group roles apply only in their own tenant. Use `getGroupIdsForTenant()`,\n never cross-tenant `getGroupIds()`, for authorization.\n- Upward visibility is opt-in and read-only: `permissions.ancestorRead`\n ({ roles, collections, maxDepth? }) lets a DESCENDANT membership contribute\n declared `<collection>.read` at an ancestor, only when no membership resolved\n there, intersected with BOTH the role's own catalog grants and the\n principal's effective permissions in that descendant, and only for SYSTEM\n roles (a tenant-scoped role sharing a declared slug is ignored). Off by default, never\n write, never lateral, and never row visibility — sibling rows stay scoped by\n tenancy/RLS. Read the permissions module before changing it.\n- Membership DENY always wins. Direct inactive membership blocks inherited\n authority; a direct active membership pins resolution instead of unioning it\n with ancestors. Read the permissions module before changing these rules.\n- AccessRequest has no generated API/MCP/CLI operations; access it through\n `AccessRequestService`. Its JSON field is `requestContext`, not reserved\n slug-scoping `context`.\n\n## Security boundaries\n\n- Generated REST/MCP operations on identity/RBAC models are list/get only.\n Route authentication does not authorize authority mutations, and these models\n are not tenant-scoped. Use permission-gated services or explicitly checked\n consumer handlers. CLI remains a local-operator surface. Preserve the\n registry assertions in `security-audit-1400.test.ts`.\n- Resource guards take the resource tenant, not the session tenant. Omit a\n session membership when targeting a different tenant; mismatches fail closed.\n `loadSessionContext().tenantAuthorization` must be checked by required-tenant\n consumers: null membership can represent inherited authority.\n- Sessions use secure UUIDs; TTL is seconds (default seven days). Access marks\n expired sessions EXPIRED. Magic-link tokens are single use.\n- Tenant switching verifies active membership before writing and rotates the\n session ID for non-null targets, revoking the old session. Persist the returned\n `SwitchTenantResult.sessionId`; `switchSessionTenant()` updates the cookie and\n preserves its security settings. Failed switches mutate nothing; null clears\n do not rotate. `SessionCollection.setSessionTenant()` is unguarded and must\n never receive an untrusted tenant ID.\n- OIDC provisioning is atomic and fail-closed. Preserve exact issuer/subject\n identifiers, claim-source email verification, unique global Person ownership,\n and transaction-bound reconciliation. Read the OIDC module and canonical\n scenario matrix before changing any provisioning path.\n\n## Entry points and validation\n\n`src/sveltekit/` owns `createSessionHandler`, `createSessionCookie`,\n`destroySessionCookie`, and `switchSessionTenant`. Use README integration examples\nrather than copying application setup into these instructions.\n\nFrom the repository root:\n\n```bash\npnpm --filter @happyvertical/smrt-users test\npnpm --filter @happyvertical/smrt-users typecheck\npnpm --filter @happyvertical/smrt-users test:postgres\n```\n\nStart with the relevant test file via `test -- src/__tests__/<file>.test.ts`.\nRun `test:postgres` for RLS, principal context, OIDC, or terminal-auth database\nchanges. `typecheck` includes Svelte accessibility checks; plain `tsc` is\ninsufficient. Follow root knowledge freshness checks before shipping.\n",
|
|
10559
|
+
"agentDoc": "# @happyvertical/smrt-users\n\nMulti-tenant identity, RBAC, hierarchical tenants, sessions, and SvelteKit auth.\n\n## Modules\n\nRead only the module relevant to the change; protocol and provisioning details\nare not prerequisites for unrelated user-package work.\n\n| Module | Scope | Module doc |\n|---|---|---|\n| `src/services/PermissionResolver.ts` | permission precedence, inherited memberships, guards, RLS, role seeding | [agents/permissions.md](agents/permissions.md) |\n| `src/services/OidcLoginService.ts`, collections and OIDC handlers | identity reconciliation, transaction boundaries, migration readiness | [agents/oidc-provisioning.md](agents/oidc-provisioning.md) |\n| `src/services/MobileAuthService.ts` | mobile handshake, bearer sessions, bootstrap extension boundary | [agents/mobile-auth.md](agents/mobile-auth.md) |\n| `src/services/TerminalAuthService.ts`, `src/collections/CliAuthApproveLimitCollection.ts` | terminal approval concurrency, shared attempt budget, retry-safe database fixtures | [agents/terminal-auth-testing.md](agents/terminal-auth-testing.md) |\n| `src/retention.ts` | expired session/token/CLI-auth reaping and retention sweep wiring | [agents/retention.md](agents/retention.md) |\n\n## Models and authority\n\n- Users are global; tenant access comes through Membership (unique user/tenant).\n User email is normalized and globally unique through readonly nullable\n `emailKey`. `profileId` is a unique cross-package reference: at most one User\n owns each non-null Profile.\n- Tenant uses STI and a materialized hierarchy, maximum depth 10.\n `hierarchyPath`/`hierarchyLevel` are derived from `parentTenantId` by\n `Tenant.save()` on every save (any caller-supplied value is recomputed) and\n descendants are re-materialized when they change; never hand-maintain them.\n Legacy rows are backfilled with `smrt db:materialize-tenant-hierarchy`\n (`materializeTenantHierarchy()`). Tests that need a corrupt path must write it\n with raw SQL (#3036).\n- Role with `tenantId = null` is available to all tenants; `isSystem` prevents\n deletion. `inheritsToDescendants` is opt-in. Seed owner/admin/member/viewer\n through `RoleCollection.seedSystemRoles()` at application initialization.\n- Group roles apply only in their own tenant. Use `getGroupIdsForTenant()`,\n never cross-tenant `getGroupIds()`, for authorization.\n- Upward visibility is opt-in and read-only: `permissions.ancestorRead`\n ({ roles, collections, maxDepth? }) lets a DESCENDANT membership contribute\n declared `<collection>.read` at an ancestor, only when no membership resolved\n there, intersected with BOTH the role's own catalog grants and the\n principal's effective permissions in that descendant, and only for SYSTEM\n roles (a tenant-scoped role sharing a declared slug is ignored). Off by default, never\n write, never lateral, and never row visibility — sibling rows stay scoped by\n tenancy/RLS. Read the permissions module before changing it.\n- Membership DENY always wins. Direct inactive membership blocks inherited\n authority; a direct active membership pins resolution instead of unioning it\n with ancestors. Read the permissions module before changing these rules.\n- AccessRequest has no generated API/MCP/CLI operations; access it through\n `AccessRequestService`. Its JSON field is `requestContext`, not reserved\n slug-scoping `context`.\n\n## Security boundaries\n\n- Generated REST/MCP operations on identity/RBAC models are list/get only.\n Route authentication does not authorize authority mutations, and these models\n are not tenant-scoped. Use permission-gated services or explicitly checked\n consumer handlers. CLI remains a local-operator surface. Preserve the\n registry assertions in `security-audit-1400.test.ts`.\n- Resource guards take the resource tenant, not the session tenant. Omit a\n session membership when targeting a different tenant; mismatches fail closed.\n `loadSessionContext().tenantAuthorization` must be checked by required-tenant\n consumers: null membership can represent inherited authority.\n- Sessions use secure UUIDs; TTL is seconds (default seven days). Access marks\n expired sessions EXPIRED. Magic-link tokens are single use.\n- Tenant switching verifies active membership before writing and rotates the\n session ID for non-null targets, revoking the old session. Persist the returned\n `SwitchTenantResult.sessionId`; `switchSessionTenant()` updates the cookie and\n preserves its security settings. Failed switches mutate nothing; null clears\n do not rotate. `SessionCollection.setSessionTenant()` is unguarded and must\n never receive an untrusted tenant ID.\n- OIDC provisioning is atomic and fail-closed. Preserve exact issuer/subject\n identifiers, claim-source email verification, unique global Person ownership,\n and transaction-bound reconciliation. Read the OIDC module and canonical\n scenario matrix before changing any provisioning path.\n\n## Entry points and validation\n\n`src/sveltekit/` owns `createSessionHandler`, `createSessionCookie`,\n`destroySessionCookie`, and `switchSessionTenant`. Use README integration examples\nrather than copying application setup into these instructions.\n\nFrom the repository root:\n\n```bash\npnpm --filter @happyvertical/smrt-users test\npnpm --filter @happyvertical/smrt-users typecheck\npnpm --filter @happyvertical/smrt-users test:postgres\n```\n\nStart with the relevant test file via `test -- src/__tests__/<file>.test.ts`.\nRun `test:postgres` for RLS, principal context, OIDC, or terminal-auth database\nchanges. `typecheck` includes Svelte accessibility checks; plain `tsc` is\ninsufficient. Follow root knowledge freshness checks before shipping.\n",
|
|
10559
10560
|
"moduleDocs": [
|
|
10560
10561
|
{
|
|
10561
10562
|
"path": "agents/permissions.md",
|
|
@@ -10572,6 +10573,11 @@
|
|
|
10572
10573
|
"module": "mobile-auth",
|
|
10573
10574
|
"content": "# Mobile authentication\n\nRead for `src/services/MobileAuthService.ts` and `/sveltekit` mobile handlers.\n\n`createMobileAuthHandlers(options)` (from `/sveltekit`) returns the mountable\nserver side of the KMP mobile contract: `authStart` (`POST auth/start`,\nserver-brokered PKCE via `OidcLoginService`), `authComplete`\n(`POST auth/complete`, code + echoed `state`/`codeVerifier` → bearer\nsession), `session.GET`/`session.DELETE` (bootstrap/logout), and\n`guard`/`withSession` — the bearer middleware for app-owned mobile routes.\nCore logic lives in `MobileAuthService` (framework-agnostic; exported from\nthe package root).\n\n- **Bearer = session id** (same convention as `TerminalAuthService`); 401\n bodies are `{ error, code }` and drive the mobile client's re-auth flow.\n- **Stateless handshake**: the OAuth `state` is an HMAC-signed token\n (secret: `stateSecret` ?? provider `clientSecret`) carrying\n nonce/provider/createdAt — full ID-token nonce verification with no\n server-side pending state. The `codeVerifier` never enters a URL: it is\n client-held per the frozen contract.\n- **Wire DTOs** come from `@happyvertical/smrt-mobile-contract`\n (`MobileAuthStartRequest` etc.) — one owning package for the Kotlin,\n Swift, and TypeScript shapes (compile-checked descriptors + parity test).\n- **Tenant options** honor `Role.inheritsToDescendants` (#1867): direct\n ACTIVE memberships plus descendants of flagged memberships (nearest\n flagged ancestor labels the option; any direct row pins; inactive direct\n rows exclude). Session binding defaults to the first DIRECT tenant —\n override with `resolveTenantId`.\n- **Hooks**: `resolveUser` (invite-gating; default provisions via\n `getOrCreateFromOidc`), `resolveTenantId`, `buildExtras` (bootstrap\n `extras`; model JSON must use `toPublicJSON({ permissions })` — #1822).\n `buildExtras` is the only app-domain bootstrap extension point. Never emit\n app fields such as `dashboard` at the response top level: they are outside\n `MobileSessionBootstrap` and the Kotlin decoder ignores them.\n- **Guard** wraps `withSessionPermissionContext`, so\n `assertOperationPermission`, tenancy context, and Postgres RLS all see the\n bearer caller; `OperationPermissionError` maps to 403 with a\n machine-readable `reason`.\n- **Uploads**: `resolveMobileUploadDedupKey` + the documented contract in\n `docs/content/architecture/mobile-upload-contract.md` (`clientCaptureId`\n field, `Idempotency-Key` header fallback); domain ingestion stays\n app-side. Framework-model writes ride `sync/apply`, not this path.\n- Configure `redirectUris` in production — RFC 8252 scheme rules always\n apply, but the allow list is the defense against redirecting authorization\n responses to attacker-controlled URIs.\n"
|
|
10574
10575
|
},
|
|
10576
|
+
{
|
|
10577
|
+
"path": "agents/terminal-auth-testing.md",
|
|
10578
|
+
"module": "terminal-auth-testing",
|
|
10579
|
+
"content": "# Terminal approval storage and regression matrix — #3076\n\nThe failed-approval budget is shared storage, keyed by unique `user_id`.\nEach UPSERT candidate uses a unique private slug, so concurrent first inserts do\nnot also collide on the inherited `(slug, context)` index. Existing rows require\nno migration: their slug is not used for lookup or authorization. The guarded\nUPSERT continues to reserve at most the configured count across service instances\nand processes. Unknown database failures propagate; they are not authentication\nsuccesses or silently converted to a rate-limit response.\n\nRisk: high (terminal authentication and shared rate-limit authority). No public\nAPI, schema, session, tenant or approval contract changes.\n\n| Behavior / trigger | Positive | Negative / failure | Actor / executor | Runtime / edge | Validation |\n|---|---|---|---|---|---|\n| First reservation candidates | Distinct private insert slugs, one user budget | Third reservation denied at limit2; old code deterministically repeats slug | Same user, real SQL observed without replacing executor | SQLite; independent PostgreSQL service connections | users `test`, `test:postgres` |\n| Concurrent invalid approvals | Three attempts reach ordinary auth denial | Ten rejected, exactly seven typed rate limits; zero attacker sessions | One attacker/user+tenant, two instances, atomic UPSERT | SQLite and PostgreSQL18 | users `test`, `test:postgres` |\n| Concurrent approval/exchange | Eight approvals share one session, one of eight exchanges succeeds | Seven exchanges expired, consumed row clears session ID | UUID user/tenant, owning services | PostgreSQL; SQLite existing lifecycle coverage | users `test`, `test:postgres` |\n| Window/release | Successful attempts release their reservation | Old-window release cannot erase new-window failure; cleanup failure cannot reverse committed approval | Existing storage executor, no retry change | SQLite | users `test` |\n| Fixture retry/reseed | Two complete fixture cycles use the same emails | No duplicate email from prior committed fixture rows | Test-owned UUIDs, explicit cleanup through public database interface | PostgreSQL; intentionally independent connections outside rollback | users `test:postgres` |\n\nBefore the repair, the candidate regression fails (one slug instead of two),\nand the second PostgreSQL fixture cycle fails its fixed-email insert. Actual CI\nalso captured a PostgreSQL duplicate `(slug, context)` error during concurrent\nfirst reservations. The fixture cleans only its own IDs in FK order, then rolls\nback its isolated handle; it must not replace real connections with one shared\ntransaction, weaken count assertions, or disable retries.\n\nRun documented users build, typecheck (including Svelte), test, test:postgres and\nverify:pack gates. PostgreSQL runs use the canonical disposable-database wrapper.\nRoot knowledge checks follow all producers. No new dialect is introduced; the\nterminal auth regression suite declares SQLite and PostgreSQL coverage.\n"
|
|
10580
|
+
},
|
|
10575
10581
|
{
|
|
10576
10582
|
"path": "agents/retention.md",
|
|
10577
10583
|
"module": "retention",
|
package/dist/sveltekit.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as OidcLoginService, D as resolveOidcProviderConfig, E as getUsersOidcConfig, S as OidcLoginError, T as encodeOidcTransaction, _ as readMobileBearerToken, a as TerminalAuthRateLimitError, g as MobileAuthService, h as MobileAuthError, i as TerminalAuthError, m as withSessionPermissionContext, o as TerminalAuthService, s as OperationPermissionError, v as validateMobileRedirectUri, w as decodeOidcTransaction, y as SessionService } from "./chunks/TerminalAuthService-
|
|
1
|
+
import { C as OidcLoginService, D as resolveOidcProviderConfig, E as getUsersOidcConfig, S as OidcLoginError, T as encodeOidcTransaction, _ as readMobileBearerToken, a as TerminalAuthRateLimitError, g as MobileAuthService, h as MobileAuthError, i as TerminalAuthError, m as withSessionPermissionContext, o as TerminalAuthService, s as OperationPermissionError, v as validateMobileRedirectUri, w as decodeOidcTransaction, y as SessionService } from "./chunks/TerminalAuthService-BDKUbg4N.js";
|
|
2
2
|
import { DiscoveryArtifactValidationError, SMRT_APP_RESULT_CONTRACT, SMRT_APP_RESULT_SCHEMA, SMRT_APP_RESULT_VERSION, SMRT_DISCOVERY_CONFORMANCE_ARTIFACT_SCHEMA, SMRT_DISCOVERY_CONFORMANCE_SCHEMA, SMRT_DISCOVERY_CONFORMANCE_VERSION, SMRT_MCP_RESULT_METADATA_KEY, canonicalizeDiscoveryArtifact, createDiscoveryConformanceArtifact, deriveCommandRequirements, validateDiscoveryConformanceArtifact } from "./app-contract.js";
|
|
3
3
|
import { ObjectRegistry, createClassNamePredicate, resolveCustomActionMetadata, resolveEffectiveActionMetadata } from "@happyvertical/smrt-core";
|
|
4
4
|
import { createLogger } from "@happyvertical/logger";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/smrt-users",
|
|
3
|
-
"version": "0.51.
|
|
3
|
+
"version": "0.51.39",
|
|
4
4
|
"smrtJsdoc": "strict",
|
|
5
5
|
"description": "Multi-tenant user management for the SMRT framework - users, tenants, roles, permissions, groups",
|
|
6
6
|
"type": "module",
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
"files": [
|
|
36
36
|
"dist",
|
|
37
37
|
"CLAUDE.md",
|
|
38
|
-
"AGENTS.md"
|
|
38
|
+
"AGENTS.md",
|
|
39
|
+
"agents"
|
|
39
40
|
],
|
|
40
41
|
"peerDependencies": {
|
|
41
42
|
"svelte": "^5.57.1"
|
|
@@ -47,18 +48,18 @@
|
|
|
47
48
|
},
|
|
48
49
|
"dependencies": {
|
|
49
50
|
"@happyvertical/logger": "^0.96.0",
|
|
50
|
-
"@happyvertical/smrt-config": "0.51.
|
|
51
|
-
"@happyvertical/smrt-core": "0.51.
|
|
52
|
-
"@happyvertical/smrt-mobile-contract": "0.51.
|
|
53
|
-
"@happyvertical/smrt-profiles": "0.51.
|
|
54
|
-
"@happyvertical/smrt-tenancy": "0.51.
|
|
55
|
-
"@happyvertical/smrt-types": "0.51.
|
|
56
|
-
"@happyvertical/smrt-ui": "0.51.
|
|
51
|
+
"@happyvertical/smrt-config": "0.51.39",
|
|
52
|
+
"@happyvertical/smrt-core": "0.51.39",
|
|
53
|
+
"@happyvertical/smrt-mobile-contract": "0.51.39",
|
|
54
|
+
"@happyvertical/smrt-profiles": "0.51.39",
|
|
55
|
+
"@happyvertical/smrt-tenancy": "0.51.39",
|
|
56
|
+
"@happyvertical/smrt-types": "0.51.39",
|
|
57
|
+
"@happyvertical/smrt-ui": "0.51.39",
|
|
57
58
|
"@happyvertical/sql": "^0.96.0",
|
|
58
59
|
"jose": "^6.2.12"
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
61
|
-
"@happyvertical/smrt-vitest": "0.51.
|
|
62
|
+
"@happyvertical/smrt-vitest": "0.51.39",
|
|
62
63
|
"@sveltejs/package": "^2.5.8",
|
|
63
64
|
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|
|
64
65
|
"@types/node": "24.13.6",
|