@collective-intelligence/external-apps-server-sdk 0.1.10 → 0.1.12

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 CHANGED
@@ -503,47 +503,41 @@ const sent = await ci.messages.send({
503
503
  reached its rate limit; it is retryable, and the client repeats it with the
504
504
  same key.
505
505
 
506
- ## Member users
506
+ ## Application users and roles
507
507
 
508
- A confidential application administers the `member` users of its own
509
- Organization: people whose only role there is `member` (Organization identity
510
- and their own Knowledge; no CI Studio or dashboard). The Organization is the
511
- one the credentials were authorized for through `organizationId`; a request
512
- cannot reach another Organization.
508
+ Use `ci.users` and `ci.roles` with a delegated user token or service
509
+ credentials. CI checks the caller's current `users.create` and `assignRoles`
510
+ permissions. These methods replace the former `ci.members` API.
513
511
 
514
512
  ```ts
515
- const ci = createServerClient({
516
- authentication: { credentials, mode: "service" },
517
- tenantUrl
518
- })
519
-
520
- const created = await ci.members.createOrGet({
513
+ const created = await ci.users.createOrGet({
521
514
  email: "info@rossi.example",
522
515
  name: "Rossi Srl",
523
- organizationId
516
+ organizationId,
517
+ roles: ["patient"],
518
+ serverRole: "onboarding" // Optional for service calls; omission uses the credential default.
524
519
  })
525
- // created.value.result: { userId, email, name, outcome }
520
+ // On success: created.value.result = { userId, email, name, created, kind }
521
+ // kind is "member" or "external_app_user".
526
522
  ```
527
523
 
528
- - `createOrGet` resolves an email to one member user. `outcome` is `created`
529
- for a new CI user, `linked` when an existing CI user joined the Organization
530
- as a member, and `existing` when the user already was one. The email is
531
- matched ignoring letter case, and concurrent or retried calls return the
532
- same `userId`. It never sends CI's activation invitation and never accepts
533
- a pending Organization invitation for the email; the application owns
534
- onboarding.
535
- - `get({ userId })`, `list({ page?, pageSize? })` (at most 100 per page),
536
- `update({ userId, name })` and `remove({ userId })` act only on member users.
537
- `update` changes the name only of a user who belongs to no other
538
- Organization. `remove` ends the `member` membership and keeps the CI user.
539
- - A user who holds any other role in the Organization (an administrator, for
540
- example) is refused with `conflict` by every operation. `get`, `update` and
541
- `remove` answer `not_found` for a user who is not in the Organization.
542
- - Reads need the `members:read` scope and writes `members:write`. Only service
543
- credentials may call them: a delegated user token or an anonymous visitor
544
- gets `operation_not_allowed`.
545
- - Only `temporarily_unavailable` is retryable (the client retries it); a
546
- creation CI refuses is a non-retryable `internal_error`.
524
+ - `createOrGet` reuses the person's auth identity. A new app user has no
525
+ Organization membership. An existing member remains a member.
526
+ - `get({ organizationId, userId })` and
527
+ `list({ organizationId, page?, pageSize? })` read users accessible to this
528
+ app. A list result contains `items`.
529
+ - `deactivate({ organizationId, userId })` ends access to the calling app for
530
+ an app user it may deactivate; it does not remove Organization membership.
531
+ - `roles.list({ organizationId })` returns `items` with role `id` and `key`.
532
+ `roles.assign({ organizationId, userId, roles })` and `roles.revoke(...)`
533
+ change this app's assignments within the caller's `assignRoles` permission.
534
+ They cannot write Organization Roles, Groups, or another app's roles.
535
+ - Pass `serverRole` on a service request to select an allowed Server Role via
536
+ `x-external-server-role`. It applies only to that request; credentials and
537
+ subsequent calls retain their default. It does not impersonate a user.
538
+ - Refusals preserve the structured error, including a reason such as
539
+ `role_not_assignable`. Non-retryable refusals are returned without retrying.
540
+ CI records the actual user, or application and Server Role, as the actor.
547
541
 
548
542
  ## Durable files
549
543
 
@@ -1219,8 +1213,12 @@ const handle = createResourceHttpHandler({
1219
1213
 
1220
1214
  `auth` is the existing `createFederatedAuth(...)` instance. Its server-only
1221
1215
  `getEntityContext` resolves current CI application, user, organization, scopes,
1222
- roles and group IDs; browser session JSON remains identity and expiry only.
1223
- Missing CI policy context denies entity access. Local Better Auth sessions do
1216
+ the user's effective app roles and App Permissions. CI never sends Group IDs or
1217
+ Platform Permissions. The browser session JSON at `<basePath>/session` carries
1218
+ `expiresAt` and an `identity` with `userId`, `organizationId`, `appId`, `kind`
1219
+ (`member` or `external_app_user`), `roles`, `appPermissions`, `email` and
1220
+ `name`; it never carries the Access token. A user without a role on the app has
1221
+ no session and no entity access. Local Better Auth sessions do
1224
1222
  not establish CI entity authority. Browser framework adapters require this
1225
1223
  verified context instead of boolean authorization. Machine gateway calls retain
1226
1224
  their separate caller policy.
@@ -1416,8 +1414,9 @@ A renewal applies the same admission rule as `/oauth/identity`:
1416
1414
 
1417
1415
  - the external Application is enabled;
1418
1416
  - the CI session is live;
1419
- - the user is not banned and is still admitted to the Organization, which
1420
- today means the Organization membership of the user and its role;
1417
+ - the user is not banned, is a member or an active External App User of the
1418
+ Organization, and holds at least one role on the app other than
1419
+ `anonymous` (Direct Role Assignments replace the roles that Groups give);
1421
1420
  - the scopes of the sign-in are still allowed.
1422
1421
 
1423
1422
  A refusal ends nothing. When the condition is corrected, the same Renewal
@@ -1499,7 +1498,7 @@ const caller = await tokens.verify(bearerToken)
1499
1498
  // userId, organizationId, applicationId, clientId, scopes, sessionId, expiresAt
1500
1499
 
1501
1500
  const identity = await tokens.identity(bearerToken, { signal: request.signal })
1502
- // the same fields, and user { id, email, name }, roles, groupIds
1501
+ // the same fields, and user { id, email, name }, kind, roles, appPermissions
1503
1502
  ```
1504
1503
 
1505
1504
  - `verify` is offline against the issuer key set: ES256 signature, issuer,
@@ -1507,7 +1506,8 @@ const identity = await tokens.identity(bearerToken, { signal: request.signal })
1507
1506
  It does not see a revocation before the token expires.
1508
1507
  - `identity` runs `verify`, then reads CI's current identity for the token and
1509
1508
  checks that it describes the same grant. Use it when the API needs the
1510
- user's roles or groups, or must stop at once when CI revokes the token. It
1509
+ user's app roles or App Permissions, or must stop at once when CI revokes
1510
+ the token or a role. It
1511
1511
  is one CI request for each call, with a 10-second limit; cache the result
1512
1512
  for as long as a role change may take to reach your API. Pass the `signal`
1513
1513
  of the request you serve: when it aborts, the CI request ends and the call
@@ -1635,3 +1635,22 @@ values use `soft_delete` and `hard_delete`, and gateway principal kinds use
1635
1635
  `detached_user` and `service_principal`. Public method and capability property
1636
1636
  names such as `softDelete` remain unchanged. External HTTP, OAuth, JSON Schema
1637
1637
  and provider values retain their required spelling at their adapter boundaries.
1638
+
1639
+ ### CI relation-member reads
1640
+
1641
+ CI-backed resources created by `defineCiEntityResource` accept the common client
1642
+ `listMembers(parentId, field, query, { signal })` operation. The shared Fetch handler
1643
+ mounts `POST /records/:parentId/relation-members/search` below the resource base
1644
+ path and forwards `{ field, ...query }` to the bound CI schema route. Existing
1645
+ verified tenant, organization, resource and user-grant checks still apply;
1646
+ `authorizeWithUserAuth` classifies this operation under `readScope`.
1647
+
1648
+ The page envelope and exact totals remain unchanged. Member records are JSON
1649
+ objects validated independently of the parent schema, as are member query field
1650
+ names; CI resolves and authorizes the actual member schema. Abort signals and
1651
+ correlation IDs pass through the proxy. All four typed read-limit metrics
1652
+ (`work`, `nodes`, `relation_ids`, `bytes`) retain `invalid_request` details
1653
+ `{ reason: "read_limit_exceeded", budget }` and rejected read outcomes. Local
1654
+ `defineEntityResource` repositories have no CI relation resolver and return
1655
+ `capability_not_supported`; the legacy CRUD facade does not expose this route.
1656
+ See the client SDK README for complete IDs, bounded includes and narrowing guidance.