mirror of
https://github.com/HeyPuter/puter.git
synced 2026-11-15 10:20:40 +00:00
33bfadc5fbfbf671f79ec18e7b547611da99ec39
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1627650abc |
refactor: make teams an optional feature (#4248)
release-please / release-please (push) Canceled after 0s
Notify HeyPuter / notify (push) Canceled after 0s
Backend Tests / changes (push) Canceled after 0s
Backend Tests / typecheck (push) Canceled after 0s
Backend Tests / test shard 1/4 (push) Canceled after 0s
Backend Tests / test shard 2/4 (push) Canceled after 0s
Backend Tests / test shard 3/4 (push) Canceled after 0s
Backend Tests / test shard 4/4 (push) Canceled after 0s
Backend Tests / test (main) (push) Canceled after 0s
Backend Tests / coverage (push) Canceled after 0s
Maintain Release Merge PR / update-release-pr (push) Canceled after 0s
* refactor: let core run without a teams registration
Teams becomes optional: `services.team` and `stores.team` may be absent, and
core stops assuming either is there.
Seventeen call sites across share, signup, account deletion and the homepage
now degrade instead of throwing: a team recipient that cannot be resolved is
"no such recipient" rather than a fault, a group share folds in nothing, and
account deletion stops asking what a seat was charged for. This generalises
the pattern `gates.ts` and `SocketService` already used.
Teams' own files take a private handle to their store and service, so the
feature's code stays free of optionality that only core needs.
No behaviour changes where Teams is registered.
* refactor: put a contract between core and teams
`core/teams.ts` holds the shapes core reads and the calls it makes, and the
registries declare the pair as provided rather than built in. The service,
store and controller are registered by whatever runs the feature.
Typing them properly turned up eight AuthController call sites the previous
commit could not see: the controller reads its stores from the built-in
registry, so an absent `team` fell to an index signature and typed as
`unknown` instead of erroring. They now go through the same optional path as
the rest.
The feature's own tests move with it. The cases in core suites that build a
team to exercise a core rule still need relocating, so those suites are red
here.
* test: stub core's seat rules, rehome the rest with the feature
A core suite can no longer build a team, so the rules that refuse a seat get
`testFixtures/seatStub.ts` instead: it answers the contract, which is all
those rules read, and puts the registry back when the test ends.
Seventeen cases move that way. Four could not: group shares and a seat's 2FA
enrolment over HTTP need the real feature and the `/teams` route, so they go
with it, as does the whole of `GroupGrants.test.ts`.
Two whoami cases asserted a seat's team through `extension.import`, which
resolves the registry rather than the stores object. They now assert the
absent case, and the behaviour they covered is asserted against
`buildUserDetails`, which takes its stores as an argument.
Suite: 12252 passed, 38 skipped.
* refactor: take the teams console out of the built-in tabs
`TabTeams`, `teamsConsole` and `teamActionIcons` are no longer built in. The
dashboard already invites a tab through its `dashboard-will-open` event, so
whatever provides Teams contributes the console the same way.
Its 113 strings go with it and register into the shipped English dictionary
at load, so `i18n('teams_*')` resolves as it did. Only `en.js` ever carried
them, so no translation is lost.
Three modules stay, because things other than the console use them:
`teamBadge` (the dashboard shell), `orgSeat` (Home, Account, Security) and
`shareTeams` (the share picker). They already render nothing when the
account has no team. `teams_account_of` stays with `teamBadge` for the same
reason, and the `share_*` and `plan_team_*` strings stay with their callers.
The GUI builds clean with no console at all, and builds it in when the tab
is contributed.
* docs: seats past the owner's current limit get no allowance
|
||
|
|
f533eb84ae |
fix(ai-ocr): check credits for the whole document before calling the provider (#4055)
* fix(ai-ocr): check credits for the whole document before calling the provider The pre-flight checked one page's cost because the page count was only known from the provider's answer, so a 130-page PDF passed on a balance worth a fraction of it and drove the account negative. The driver now estimates pages before the call: a PDF's own count (read from its page tree, including compressed object streams), capped by a `pages` selection; one page for images and Textract, whose synchronous API reads single-page documents. Other documents and PDFs it can't read count 20 pages per MB, Mistral's 1,000-page limit at its 50 MB size cap. The estimated cost is checked and held while the provider runs, so concurrent calls see it. Usage is still metered from the pages the provider reports. * fix(ai-ocr): price the credit hold at the AI cost factor Billing scales OCR usage by the ai.cost.factor hook, but the hold was sized at the raw cost, so a balance covering N pages passed the check and was then charged more. Hold through reserveAiCredits like the other AI drivers. |
||
|
|
9f615cc632 |
feat: add the two-team fixture and group permission grants
Two tickets, together because the fixture has no behaviour of its own — the
grant tests are its first real use, and "a grant to team A must not
resolve for B's members" is exactly a two-team assertion.
PUT-1719. Every query resolving team-scoped data has to take the
team as a parameter rather than infer it. One that forgets returns the
right rows against a database holding a single team, so a one-team
fixture does not give weaker coverage — it gives false confidence.
The fixture provides two teams, each with its own master and two
activated seats, plus a user in neither. Each team having its own master
is also what the shipped `max_teams_per_user: 1` requires, so it runs
against the real cap rather than lifting it the way the existing team suites
have to. Seats are activated before use: provisioning leaves
`requires_email_confirmation` set and `requireVerified` rejects them outright,
so an unactivated seat cannot call anything and every authorization assertion
built on one would be vacuous.
PUT-1725. The write half of group grants; the read half already worked, since
`#scanUserGroup` joins `jct_user_group` itself and resolves for whoever is a
member at scan time.
PermissionStore resolveGroupId, listGroupMemberUuids,
upsertUserGroupPerm, deleteUserGroupPerm,
auditUserGroupPerm
PermissionService grantUserGroupPermission, revokeUserGroupPermission
Both rewrite the permission first, so `fs:/path:mode` collapses to
`fs:<uuid>:mode` and a revoke names the same string the grant wrote; both gate
on `canManagePermission`; both audit into the existing
`audit_user_to_group_permissions`.
The delete is scoped to the issuer, so one issuer's revoke cannot drop
another's identical grant — the PK is (user_id, group_id, permission) and
user_id is the issuer.
Cache invalidation goes through `bumpCacheGenerations` with every member uuid
at once. That already announces to peer regions in a single event, so the
fan-out costs one broadcast rather than one per member.
There is no flat-KV equivalent for group grants, so unlike the user-to-user
path there is no second write to keep consistent and no second invalidation
surface.
Closes PUT-1719 and PUT-1725.
|