@collective-intelligence/external-apps-server-sdk 0.1.4 → 0.1.6
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 +157 -6
- package/dist/admin.d.ts +12 -0
- package/dist/auth/federated.d.ts +4 -0
- package/dist/auth/federated.js +1 -1
- package/dist/gateway.js +1 -1
- package/dist/index.d.ts +124 -0
- package/dist/index.js +1 -1
- package/dist/persistence/drizzle.d.ts +4 -0
- package/dist/persistence/drizzle.js +1 -1
- package/dist/runtime/effect.js +1 -1
- package/dist/tools/ai-sdk.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -427,6 +427,54 @@ succeeded before the new turn started count. A turn is
|
|
|
427
427
|
subject, never with the application's scopes. Visitors are separate owners:
|
|
428
428
|
one visitor never reads another visitor's conversation.
|
|
429
429
|
|
|
430
|
+
## Messages
|
|
431
|
+
|
|
432
|
+
`messages.send` sends one message through a messaging connection of the
|
|
433
|
+
Organization, for example a Telegram bot or a WhatsApp Business Account. The
|
|
434
|
+
application needs the `messaging:send` scope, and an administrator must grant
|
|
435
|
+
the connection to the application on its administration page.
|
|
436
|
+
|
|
437
|
+
```ts
|
|
438
|
+
const sent = await ci.messages.send({
|
|
439
|
+
connectionId,
|
|
440
|
+
content: { kind: "text", text: "Your order is ready." },
|
|
441
|
+
idempotencyKey: `order-${orderId}-ready`,
|
|
442
|
+
organizationId,
|
|
443
|
+
target: { conversation, mode: "continue" }
|
|
444
|
+
})
|
|
445
|
+
// sent.value.result: { conversation, messageId }
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
- `target` continues a conversation with the Conversation Reference of an
|
|
449
|
+
earlier message (`{ mode: "continue", conversation }`), or starts one with
|
|
450
|
+
the recipient fields of the vendor (`{ mode: "start_new", recipient }`).
|
|
451
|
+
- `content` is a text, or `{ kind: "voice", text, voice }` for a text that CI
|
|
452
|
+
speaks.
|
|
453
|
+
- `sender` holds the sender fields of the vendor, for example
|
|
454
|
+
`{ phoneNumberId }`. It is required when the account has more than one
|
|
455
|
+
sender. `service` names the vendor service when the connection has more
|
|
456
|
+
than one.
|
|
457
|
+
- The result is the Message Receipt: the message id of the vendor and the
|
|
458
|
+
Conversation Reference that continues the conversation. It means that the
|
|
459
|
+
vendor accepted the message, not that a person received it.
|
|
460
|
+
- `idempotencyKey` (at most 256 characters; generated when omitted) makes a
|
|
461
|
+
repeat safe. A repeat with the same key and content returns the first
|
|
462
|
+
outcome and sends nothing. A repeat with the same key and other content
|
|
463
|
+
returns `conflict`. Use your own key when your server can repeat a send
|
|
464
|
+
after a crash.
|
|
465
|
+
- CI sends once and never retries a failed send. A failed send returns
|
|
466
|
+
`message_send_failed` with a `sendErrorCode`, for example `window_closed`,
|
|
467
|
+
`recipient_unreachable`, `template_required` or `transport`. The same key
|
|
468
|
+
returns the same failure: use a new key to send again.
|
|
469
|
+
- `send_outcome_unknown` means that the first send with the key has no
|
|
470
|
+
recorded outcome: it still runs, or CI stopped before it recorded the
|
|
471
|
+
outcome. CI does not send again for the key. Repeat the call later; if the
|
|
472
|
+
answer stays the same, check with the vendor before you send with a new key.
|
|
473
|
+
- `not_found` means that the connection does not exist or is not granted to
|
|
474
|
+
the application. `rate_limited` (HTTP 429) means that the connection
|
|
475
|
+
reached its rate limit; it is retryable, and the client repeats it with the
|
|
476
|
+
same key.
|
|
477
|
+
|
|
430
478
|
## Member users
|
|
431
479
|
|
|
432
480
|
A confidential application administers the `member` users of its own
|
|
@@ -503,11 +551,18 @@ const links = await ci.users.listCompanyLinks({ organizationId, userId })
|
|
|
503
551
|
- A delegated user's `/application/v1/resources` and `knowledge_*` calls, and
|
|
504
552
|
the Agents, Skills and workflows the user runs, carry the user's links to
|
|
505
553
|
Knowledge policy as `subject.linkedCompanyIds`, and a policy reads the
|
|
506
|
-
entity id as `resource` path `["id"]`.
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
554
|
+
entity id as `resource` path `["id"]`. CI also sets `subject.access`:
|
|
555
|
+
`"read"` for gets, lists, searches, facets, autocomplete, traversal and
|
|
556
|
+
retrieval, `"write"` for creates, updates, deletes and relation writes. The
|
|
557
|
+
operation sets it; a caller cannot. A policy that does not test `access`
|
|
558
|
+
applies to reads and writes alike.
|
|
559
|
+
- To let `member`-role users write only their own companies but read every
|
|
560
|
+
company (for example through member-run Agents), declare a `deny` `filter`
|
|
561
|
+
policy on the company schema: subject match `user.role` equals `member` and
|
|
562
|
+
`access` equals `write`, rule "entity id not in `linkedCompanyIds`". Updates
|
|
563
|
+
and deletes of any other company, and creates, then fail with `forbidden`;
|
|
564
|
+
gets, lists and searches still return it. Without the `access` clause the
|
|
565
|
+
same policy also hides other companies from reads. Other roles and service
|
|
511
566
|
credentials are unaffected.
|
|
512
567
|
- The policy binds an execution only while it acts as the member. An Agent or
|
|
513
568
|
Skill tool bound to a fixed user, or a workflow that runs as another user or
|
|
@@ -1149,7 +1204,100 @@ The store persists only hashed opaque-cookie state, token grants and revisions;
|
|
|
1149
1204
|
the browser receives a `Secure`, `HttpOnly`, `SameSite=Lax` host cookie. Every
|
|
1150
1205
|
session lookup revalidates the short-lived CI identity. Revoked or expired CI
|
|
1151
1206
|
access ends application authorization on the next validation. A confidential
|
|
1152
|
-
OAuth client may supply `clientSecret`; a public PKCE client omits it.
|
|
1207
|
+
OAuth client may supply `clientSecret`; a public PKCE client omits it. The
|
|
1208
|
+
client type decides how long the User session lasts; see
|
|
1209
|
+
[Session lifetime and renewal](#session-lifetime-and-renewal).
|
|
1210
|
+
|
|
1211
|
+
### Session lifetime and renewal
|
|
1212
|
+
|
|
1213
|
+
`sessionTtlSeconds` sets the Session lifetime: the time from sign-in to the
|
|
1214
|
+
end of the User session. The default is `86400` (one day). The SDK accepts an
|
|
1215
|
+
integer from `300` to `604800` (seven days).
|
|
1216
|
+
|
|
1217
|
+
A User session lasts its Session lifetime only with renewal. Without renewal,
|
|
1218
|
+
the User session ends when its Access token expires, 300 seconds after
|
|
1219
|
+
sign-in, whatever the value of `sessionTtlSeconds`. The Access token lifetime
|
|
1220
|
+
is always 300 seconds. There is no setting for it.
|
|
1221
|
+
|
|
1222
|
+
Renewal needs these three conditions:
|
|
1223
|
+
|
|
1224
|
+
- The external Application is confidential at CI.
|
|
1225
|
+
- `createFederatedAuth` gets the `clientSecret` of that Application.
|
|
1226
|
+
- The user signed in after the upgrade to an SDK version that renews. An
|
|
1227
|
+
earlier cookie or store record holds no Renewal credential. That User
|
|
1228
|
+
session ends at its Access token expiry.
|
|
1229
|
+
|
|
1230
|
+
When the three conditions are true, CI returns a Renewal credential at
|
|
1231
|
+
sign-in. On the wire it is the OAuth `refresh_token`. The SDK keeps it in the
|
|
1232
|
+
session record and uses it to get a new Access token with no browser redirect.
|
|
1233
|
+
The application code does not change.
|
|
1234
|
+
|
|
1235
|
+
A public client has no client secret, so it gets no Renewal credential. Its
|
|
1236
|
+
User session lasts 300 seconds. To continue, the application sends the browser
|
|
1237
|
+
to `<basePath>/login` again, as before. A `fetch` call or a form post cannot
|
|
1238
|
+
follow that redirect. For a public client, `createFederatedAuth` still accepts
|
|
1239
|
+
each `sessionTtlSeconds` value in the range and gives no warning.
|
|
1240
|
+
|
|
1241
|
+
`getSession`, `getAccessToken`, `getEntityContext` and
|
|
1242
|
+
`GET <basePath>/session` are the session lookups. With renewal, each lookup
|
|
1243
|
+
first gets a new Access token when the current one is expired or expires in 30
|
|
1244
|
+
seconds or less. Then it checks the current identity at `/oauth/identity`. A
|
|
1245
|
+
lookup never returns an expired Access token. Lookups at the same time share
|
|
1246
|
+
one renewal request.
|
|
1247
|
+
|
|
1248
|
+
The SDK writes the cookie or the store record one time, at sign-in. A renewal
|
|
1249
|
+
writes no cookie and no store record. A renewed Access token stays only in
|
|
1250
|
+
process memory. Each `createFederatedAuth` instance keeps at most 5000 of
|
|
1251
|
+
them, separate from each other instance. A restart loses them, and the next
|
|
1252
|
+
lookup renews again.
|
|
1253
|
+
|
|
1254
|
+
A Federated authorization is the record that CI keeps of one sign-in to one
|
|
1255
|
+
external Application. It lasts at most 604800 seconds from sign-in, and never
|
|
1256
|
+
longer than the CI session of the user. The User session ends at the earlier
|
|
1257
|
+
of these two times:
|
|
1258
|
+
|
|
1259
|
+
- sign-in plus `sessionTtlSeconds`;
|
|
1260
|
+
- the end of the Federated authorization.
|
|
1261
|
+
|
|
1262
|
+
`expiresAt` of the session reports that end. It is the same at each lookup,
|
|
1263
|
+
because a lookup does not extend the User session. Without a Renewal
|
|
1264
|
+
credential, `expiresAt` stays the Access token expiry.
|
|
1265
|
+
|
|
1266
|
+
A lookup has one of three results:
|
|
1267
|
+
|
|
1268
|
+
- **A session.** CI accepts the identity, after a renewal when one is
|
|
1269
|
+
necessary.
|
|
1270
|
+
- **`null`**, and `401` on `GET <basePath>/session`. CI refuses the user or
|
|
1271
|
+
the Federated authorization: it answers `invalid_grant` to the renewal, or
|
|
1272
|
+
it refuses the identity. The result is also `null` after the end of the User
|
|
1273
|
+
session. Send the user to the login route.
|
|
1274
|
+
- **`ApplicationUserAuthUnavailableError`**, and `503` on
|
|
1275
|
+
`GET <basePath>/session`. The client secret is wrong or rotated
|
|
1276
|
+
(`invalid_client`), CI gives another OAuth error, or CI does not answer. The
|
|
1277
|
+
User session stays. It returns when the fault is corrected, with no
|
|
1278
|
+
sign-in.
|
|
1279
|
+
|
|
1280
|
+
A renewal applies the same admission rule as `/oauth/identity`:
|
|
1281
|
+
|
|
1282
|
+
- the external Application is enabled;
|
|
1283
|
+
- the CI session is live;
|
|
1284
|
+
- the user is not banned and is still admitted to the Organization, which
|
|
1285
|
+
today means the Organization membership of the user and its role;
|
|
1286
|
+
- the scopes of the sign-in are still allowed.
|
|
1287
|
+
|
|
1288
|
+
A refusal ends nothing. When the condition is corrected, the same Renewal
|
|
1289
|
+
credential renews again. A Federated authorization ends for good only by one
|
|
1290
|
+
of these events: logout, a new sign-in in the same User session, its limit of
|
|
1291
|
+
604800 seconds, or the end of the CI session.
|
|
1292
|
+
|
|
1293
|
+
`POST <basePath>/logout` presents the Renewal credential to CI, and CI ends
|
|
1294
|
+
the Federated authorization. If CI does not answer, the route answers `503`
|
|
1295
|
+
and still clears the User session. That Federated authorization then ends at
|
|
1296
|
+
its limit or with its CI session.
|
|
1297
|
+
|
|
1298
|
+
An application that does not use this SDK finds the CI token and logout
|
|
1299
|
+
contract in
|
|
1300
|
+
[Access token renewal](../../../docs/architecture/external-app-gateway.md#access-token-renewal).
|
|
1153
1301
|
|
|
1154
1302
|
### Configure from the CLI enrollment
|
|
1155
1303
|
|
|
@@ -1159,6 +1307,9 @@ OAuth client may supply `clientSecret`; a public PKCE client omits it.
|
|
|
1159
1307
|
`CI_CLIENT_SECRET`. `readApplicationEnrollment` reads those variables, so the
|
|
1160
1308
|
application names none of them. It throws a `TypeError` that lists every
|
|
1161
1309
|
missing variable. Pass the same prefix as `--prefix` when it is not `CI_`.
|
|
1310
|
+
`ci apps env <application>` prints the same variables for an application that
|
|
1311
|
+
already exists, for example to copy them into a deployment pipeline; it leaves
|
|
1312
|
+
out `CI_CLIENT_SECRET`, which CI shows only once.
|
|
1162
1313
|
|
|
1163
1314
|
```ts
|
|
1164
1315
|
import {
|
package/dist/admin.d.ts
CHANGED
|
@@ -4965,6 +4965,7 @@ declare const createAdministrationApi: (client: Client$1) => {
|
|
|
4965
4965
|
description: string | null;
|
|
4966
4966
|
directChildCount: number;
|
|
4967
4967
|
directMemberCount: number;
|
|
4968
|
+
fqn: string | null;
|
|
4968
4969
|
id: string;
|
|
4969
4970
|
inheritedMembershipImpact: {
|
|
4970
4971
|
descendantGroupCount: number;
|
|
@@ -4973,6 +4974,11 @@ declare const createAdministrationApi: (client: Client$1) => {
|
|
|
4973
4974
|
};
|
|
4974
4975
|
name: string;
|
|
4975
4976
|
organizationId: string;
|
|
4977
|
+
package: {
|
|
4978
|
+
fqn: string;
|
|
4979
|
+
managed: boolean;
|
|
4980
|
+
readonly: boolean;
|
|
4981
|
+
} | null;
|
|
4976
4982
|
parentGroupId: string | null;
|
|
4977
4983
|
parentPath: Array<{
|
|
4978
4984
|
id: string;
|
|
@@ -5001,6 +5007,7 @@ declare const createAdministrationApi: (client: Client$1) => {
|
|
|
5001
5007
|
description: string | null;
|
|
5002
5008
|
directChildCount: number;
|
|
5003
5009
|
directMemberCount: number;
|
|
5010
|
+
fqn: string | null;
|
|
5004
5011
|
id: string;
|
|
5005
5012
|
inheritedMembershipImpact: {
|
|
5006
5013
|
descendantGroupCount: number;
|
|
@@ -5009,6 +5016,11 @@ declare const createAdministrationApi: (client: Client$1) => {
|
|
|
5009
5016
|
};
|
|
5010
5017
|
name: string;
|
|
5011
5018
|
organizationId: string;
|
|
5019
|
+
package: {
|
|
5020
|
+
fqn: string;
|
|
5021
|
+
managed: boolean;
|
|
5022
|
+
readonly: boolean;
|
|
5023
|
+
} | null;
|
|
5012
5024
|
parentGroupId: string | null;
|
|
5013
5025
|
parentPath: Array<{
|
|
5014
5026
|
id: string;
|
package/dist/auth/federated.d.ts
CHANGED
|
@@ -125,6 +125,10 @@ declare class FederatedAuthRejectedError extends Error {
|
|
|
125
125
|
export type FederatedGrant = Readonly<{
|
|
126
126
|
accessToken: string;
|
|
127
127
|
expiresAt: number;
|
|
128
|
+
/** Renewal credential of the Federated authorization; set together with `refreshExpiresAt`. */
|
|
129
|
+
refreshToken?: string;
|
|
130
|
+
/** Epoch milliseconds at which the Renewal credential stops; set together with `refreshToken`. */
|
|
131
|
+
refreshExpiresAt?: number;
|
|
128
132
|
}>;
|
|
129
133
|
export type FederatedLogin = Readonly<{
|
|
130
134
|
status: "idle";
|