@k9o/core 1.2.0 → 1.3.0
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/CHANGELOG.md +45 -0
- package/README.md +168 -17
- package/dist/{chunk-O2ZTV6YN.js → chunk-KC4EDMBF.js} +61 -3
- package/dist/chunk-KC4EDMBF.js.map +1 -0
- package/dist/{chunk-2NDFTHUB.js → chunk-UL53GNYM.js} +23 -5
- package/dist/chunk-UL53GNYM.js.map +1 -0
- package/dist/http.d.ts +2 -0
- package/dist/http.js +2 -1
- package/dist/index.d.ts +563 -517
- package/dist/index.js +170 -421
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/url-grammar.d.ts +32 -16
- package/dist/url-grammar.js +5 -1
- package/package.json +4 -4
- package/src/audit.ts +16 -26
- package/src/compute/llms.ts +55 -33
- package/src/functions.ts +60 -27
- package/src/http.ts +5 -1
- package/src/index.ts +16 -17
- package/src/me.ts +69 -85
- package/src/migrations.ts +61 -11
- package/src/org.ts +138 -140
- package/src/orgs.ts +16 -3
- package/src/policies.ts +63 -24
- package/src/projects.ts +58 -22
- package/src/realtime.ts +21 -200
- package/src/region.ts +83 -3
- package/src/storage-buckets.ts +17 -5
- package/src/studio/workflows.ts +8 -8
- package/src/types.ts +3 -3
- package/src/url-grammar.ts +52 -25
- package/dist/chunk-2NDFTHUB.js.map +0 -1
- package/dist/chunk-O2ZTV6YN.js.map +0 -1
- package/src/metadata.ts +0 -130
package/src/org.ts
CHANGED
|
@@ -7,36 +7,55 @@
|
|
|
7
7
|
* across accessible orgs) — `client.org` is the singular bound-org
|
|
8
8
|
* namespace with member / group / smtp / audit / gate sub-namespaces.
|
|
9
9
|
*
|
|
10
|
-
* Org-plane URL grammar: requests
|
|
11
|
-
*
|
|
12
|
-
* prefix used by project-plane requests. The gateway resolves the org
|
|
13
|
-
* context from the subdomain.
|
|
10
|
+
* Org-plane URL grammar: requests go to the org's API host (`<orgSlug>.api.<apex>`) WITHOUT the
|
|
11
|
+
* `@<projectSlug>/` prefix used by project-plane requests. The gateway resolves the org context from the host.
|
|
14
12
|
*/
|
|
15
13
|
|
|
16
14
|
import { request, type HttpClientConfig } from "./http.ts";
|
|
17
15
|
import { orgPath } from "./url-grammar.ts";
|
|
18
16
|
import type { Envelope } from "./envelope.ts";
|
|
19
17
|
import type { LLMModelId } from "./compute/llms.ts";
|
|
18
|
+
import type { Org } from "./orgs.ts";
|
|
20
19
|
|
|
21
20
|
// ----------------------------------------------------------------------
|
|
22
21
|
// Types
|
|
23
22
|
// ----------------------------------------------------------------------
|
|
24
23
|
|
|
25
24
|
export type OrgMember = {
|
|
26
|
-
/** `
|
|
25
|
+
/** `usr_<base62>`. */
|
|
27
26
|
userId: string;
|
|
27
|
+
orgId: string;
|
|
28
28
|
email: string;
|
|
29
|
-
|
|
29
|
+
displayName: string;
|
|
30
|
+
/** Org-level role. */
|
|
30
31
|
role: "ORG_OWNER" | "ORG_ADMIN" | "ORG_BILLING_ADMIN" | "ORG_MEMBER";
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
invitedAt: string;
|
|
33
|
+
/** `null` until the invitation is accepted. */
|
|
34
|
+
acceptedAt: string | null;
|
|
35
|
+
status: "active" | "suspended";
|
|
36
|
+
/** `invited` until accepted, then the same as `status`. */
|
|
37
|
+
state: "invited" | "active" | "suspended";
|
|
38
|
+
suspendedAt: string | null;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Answer of `members.invite` when the email has no account yet (HTTP 202): an invitation was created
|
|
43
|
+
* instead of a member. `delivery` says whether the invitation email went out.
|
|
44
|
+
*/
|
|
45
|
+
export type OrgInviteResult = {
|
|
46
|
+
invitation: { id: string; orgId: string; email: string; role: OrgMember["role"]; expiresAt: string };
|
|
47
|
+
delivery: "sent" | "not_configured" | "failed";
|
|
33
48
|
};
|
|
34
49
|
|
|
35
50
|
export type OrgGroup = {
|
|
36
51
|
/** `grp_<base62>`. */
|
|
37
52
|
id: string;
|
|
53
|
+
orgId: string;
|
|
38
54
|
name: string;
|
|
39
|
-
|
|
55
|
+
description: string | null;
|
|
56
|
+
/** Groups come from an identity provider. */
|
|
57
|
+
source: "idp";
|
|
58
|
+
sourceGroupId: string;
|
|
40
59
|
createdAt: string;
|
|
41
60
|
};
|
|
42
61
|
|
|
@@ -44,7 +63,7 @@ export type OrgRoleGrant = {
|
|
|
44
63
|
/** `grt_<base62>`. */
|
|
45
64
|
id: string;
|
|
46
65
|
userId: string;
|
|
47
|
-
role: "ORG_ADMIN" | "ORG_BILLING_ADMIN";
|
|
66
|
+
role: "ORG_OWNER" | "ORG_ADMIN" | "ORG_BILLING_ADMIN" | "ORG_AUDITOR" | "ORG_MEMBER";
|
|
48
67
|
grantedBy: string;
|
|
49
68
|
grantedAt: string;
|
|
50
69
|
revokedAt: string | null;
|
|
@@ -53,74 +72,90 @@ export type OrgRoleGrant = {
|
|
|
53
72
|
};
|
|
54
73
|
|
|
55
74
|
/**
|
|
56
|
-
* Org-level audit event
|
|
57
|
-
*
|
|
58
|
-
* Event types (closed set at v2.1.132):
|
|
59
|
-
* - `data.write.org.member_invited`
|
|
60
|
-
* - `data.write.org.member_removed`
|
|
61
|
-
* - `data.write.org.role_granted`
|
|
62
|
-
* - `data.write.org.role_revoked`
|
|
63
|
-
* - `data.write.org.idp_config_changed`
|
|
64
|
-
* - `data.write.org.settings_updated`
|
|
65
|
-
*
|
|
66
|
-
* `targetKind` is `org` for all; `targetId` is the orgId.
|
|
75
|
+
* Org-level audit event: member invited or removed, role granted or revoked, identity provider
|
|
76
|
+
* or settings changed.
|
|
67
77
|
*/
|
|
68
78
|
export type OrgAuditEvent = {
|
|
69
79
|
id: string;
|
|
70
80
|
type: string;
|
|
71
81
|
actorId: string | null;
|
|
72
|
-
targetKind:
|
|
73
|
-
targetId: string;
|
|
82
|
+
targetKind: string | null;
|
|
83
|
+
targetId: string | null;
|
|
74
84
|
payload: Record<string, unknown>;
|
|
75
|
-
|
|
85
|
+
createdAt: string;
|
|
76
86
|
requestId: string | null;
|
|
77
87
|
traceId: string | null;
|
|
78
88
|
};
|
|
79
89
|
|
|
80
90
|
/**
|
|
81
|
-
* Org SMTP configuration
|
|
82
|
-
*
|
|
91
|
+
* Org SMTP configuration, as the gateway takes it in the `smtpConfig` field of PATCH /org.
|
|
92
|
+
* The password is never sent: `passwordRef` is a reference to a stored secret.
|
|
83
93
|
*/
|
|
84
94
|
export type SmtpConfig = {
|
|
85
95
|
host: string;
|
|
86
96
|
port: number;
|
|
87
97
|
username: string;
|
|
88
|
-
/**
|
|
98
|
+
/** Reference to the stored SMTP password; opaque token. */
|
|
89
99
|
passwordRef: string;
|
|
90
|
-
|
|
91
|
-
fromName
|
|
92
|
-
encryption: "none" | "starttls" | "tls";
|
|
93
|
-
replyToEmail?: string | undefined;
|
|
100
|
+
fromAddress: string;
|
|
101
|
+
fromName?: string | undefined;
|
|
94
102
|
};
|
|
95
103
|
|
|
96
104
|
export type SmtpTestEmailInput = {
|
|
97
105
|
to: string;
|
|
98
|
-
|
|
99
|
-
fromOverride?: string | undefined;
|
|
106
|
+
subject?: string | undefined;
|
|
100
107
|
};
|
|
101
108
|
|
|
102
109
|
export type SmtpTestEmailResult = {
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
110
|
+
accepted: boolean;
|
|
111
|
+
/** Which SMTP configuration serves the org: `org` when it has its own, else `platform`. */
|
|
112
|
+
resolvedTier: "org" | "platform";
|
|
113
|
+
to: string;
|
|
114
|
+
/** `true` while the gateway does not send the message itself. */
|
|
115
|
+
dryRun: boolean;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export type OrgDefaultLlm = {
|
|
119
|
+
orgId: string;
|
|
120
|
+
defaultModelId: string;
|
|
121
|
+
updatedAt: string;
|
|
122
|
+
updatedBy: string | null;
|
|
108
123
|
};
|
|
109
124
|
|
|
125
|
+
export type OrgIdpProviderKind =
|
|
126
|
+
| "google" | "github" | "microsoft" | "oidc" | "saml" | "scim" | "ldap" | "active_directory" | "apple" | "facebook" | "twitter";
|
|
127
|
+
|
|
110
128
|
export type OrgIdpProvider = {
|
|
111
|
-
/** `idp_<base62>`. */
|
|
112
129
|
id: string;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
130
|
+
idpProvider: OrgIdpProviderKind;
|
|
131
|
+
displayName: string;
|
|
132
|
+
clientId: string;
|
|
116
133
|
enabled: boolean;
|
|
117
134
|
createdAt: string;
|
|
118
135
|
};
|
|
119
136
|
|
|
137
|
+
/** Body of POST /identity-providers. `clientSecretRef` is a reference to a stored secret, never the secret itself. */
|
|
120
138
|
export type CreateOrgIdpInput = {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
139
|
+
idpProvider: OrgIdpProviderKind;
|
|
140
|
+
displayName: string;
|
|
141
|
+
clientId: string;
|
|
142
|
+
clientSecretRef: string;
|
|
143
|
+
tierGating: "free_tier_ok" | "ridge_plus";
|
|
144
|
+
redirectUri?: string | undefined;
|
|
145
|
+
metadataUrl?: string | null | undefined;
|
|
146
|
+
attributeMap?: Record<string, unknown> | undefined;
|
|
147
|
+
enabled?: boolean | undefined;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/** Body of PATCH /identity-providers/<id>. */
|
|
151
|
+
export type UpdateOrgIdpInput = {
|
|
152
|
+
displayName?: string | undefined;
|
|
153
|
+
clientId?: string | undefined;
|
|
154
|
+
clientSecretRef?: string | undefined;
|
|
155
|
+
redirectUri?: string | undefined;
|
|
156
|
+
metadataUrl?: string | null | undefined;
|
|
157
|
+
attributeMap?: Record<string, unknown> | undefined;
|
|
158
|
+
enabled?: boolean | undefined;
|
|
124
159
|
};
|
|
125
160
|
|
|
126
161
|
// ----------------------------------------------------------------------
|
|
@@ -129,23 +164,24 @@ export type CreateOrgIdpInput = {
|
|
|
129
164
|
|
|
130
165
|
function makeMembersNamespace(config: HttpClientConfig) {
|
|
131
166
|
return {
|
|
132
|
-
/** GET /members (org-plane LIST). */
|
|
133
|
-
async list(opts?: {
|
|
167
|
+
/** GET /members (org-plane LIST). The route is not paged; it filters by userId, role, acceptanceStatus, status and state. */
|
|
168
|
+
async list(opts?: {
|
|
169
|
+
userId?: string | undefined; role?: OrgMember["role"] | undefined;
|
|
170
|
+
acceptanceStatus?: "accepted" | "pending" | undefined; status?: "active" | "suspended" | undefined; state?: string | undefined;
|
|
171
|
+
}): Promise<Envelope<ReadonlyArray<OrgMember>>> {
|
|
134
172
|
return request(config, { method: "GET", path: orgPath("members"), query: opts });
|
|
135
173
|
},
|
|
136
174
|
|
|
137
|
-
/**
|
|
138
|
-
|
|
175
|
+
/**
|
|
176
|
+
* POST /members — add a member by email. An existing user becomes a member at once (201, the member row);
|
|
177
|
+
* an unknown email gets an invitation (202, `{ invitation, delivery }`).
|
|
178
|
+
*/
|
|
179
|
+
async invite(input: { email: string; role: OrgMember["role"] }): Promise<Envelope<OrgMember | OrgInviteResult>> {
|
|
139
180
|
return request(config, { method: "POST", path: orgPath("members"), body: input });
|
|
140
181
|
},
|
|
141
182
|
|
|
142
|
-
/**
|
|
143
|
-
async
|
|
144
|
-
return request(config, { method: "GET", path: orgPath(`members/${encodeURIComponent(userId)}`) });
|
|
145
|
-
},
|
|
146
|
-
|
|
147
|
-
/** DELETE /members/<userId> — remove a member from the org. */
|
|
148
|
-
async remove(userId: string): Promise<Envelope<{ removed: boolean }>> {
|
|
183
|
+
/** DELETE /members/<userId> — remove a member from the org. The gateway answers 204 with no body. */
|
|
184
|
+
async remove(userId: string): Promise<Envelope<undefined>> {
|
|
149
185
|
return request(config, { method: "DELETE", path: orgPath(`members/${encodeURIComponent(userId)}`) });
|
|
150
186
|
},
|
|
151
187
|
};
|
|
@@ -154,104 +190,78 @@ function makeMembersNamespace(config: HttpClientConfig) {
|
|
|
154
190
|
function makeGroupsNamespace(config: HttpClientConfig) {
|
|
155
191
|
return {
|
|
156
192
|
/** GET /groups (org-plane LIST). */
|
|
157
|
-
async list(opts?: {
|
|
193
|
+
async list(opts?: { userId?: string | undefined }): Promise<Envelope<ReadonlyArray<OrgGroup>>> {
|
|
158
194
|
return request(config, { method: "GET", path: orgPath("groups"), query: opts });
|
|
159
195
|
},
|
|
160
196
|
|
|
161
|
-
/**
|
|
162
|
-
async create(input: { name: string }): Promise<Envelope<OrgGroup>> {
|
|
163
|
-
return request(config, { method: "POST", path: orgPath("groups"), body: input });
|
|
164
|
-
},
|
|
165
|
-
|
|
166
|
-
/** GET /groups/<groupId> — single-read (pre-cement existing endpoint). */
|
|
197
|
+
/** GET /groups/<groupId> — single-read. */
|
|
167
198
|
async get(groupId: string): Promise<Envelope<OrgGroup>> {
|
|
168
199
|
return request(config, { method: "GET", path: orgPath(`groups/${encodeURIComponent(groupId)}`) });
|
|
169
200
|
},
|
|
170
201
|
|
|
171
|
-
/** DELETE /groups/<groupId> — remove a group. */
|
|
172
|
-
async delete(groupId: string): Promise<Envelope<{ deleted: boolean }>> {
|
|
173
|
-
return request(config, { method: "DELETE", path: orgPath(`groups/${encodeURIComponent(groupId)}`) });
|
|
174
|
-
},
|
|
175
202
|
};
|
|
176
203
|
}
|
|
177
204
|
|
|
178
205
|
function makeOrgAuditLogNamespace(config: HttpClientConfig) {
|
|
179
206
|
return {
|
|
180
207
|
/**
|
|
181
|
-
* GET /audit-log (org-plane).
|
|
182
|
-
* Distinct from project-plane `client.audit.query()` which routes to
|
|
183
|
-
* `@<projectSlug>/audit-log`. Org-plane events cover the 6-event family
|
|
184
|
-
* (member_invited/removed/role_granted/revoked/
|
|
185
|
-
* idp_config_changed/settings_updated).
|
|
208
|
+
* GET /audit-log (org-plane), newest first. The route reads `type` and `limit` (1 to 500, default 100) only.
|
|
209
|
+
* Distinct from project-plane `client.audit.query()` which routes to `@<projectSlug>/audit-log`.
|
|
186
210
|
*/
|
|
187
|
-
async query(opts?: {
|
|
188
|
-
since?: string | undefined; until?: string | undefined; type?: string | undefined; actorId?: string | undefined;
|
|
189
|
-
targetKind?: string | undefined; targetId?: string | undefined; limit?: number | undefined; cursor?: string | undefined;
|
|
190
|
-
}): Promise<Envelope<ReadonlyArray<OrgAuditEvent>>> {
|
|
211
|
+
async query(opts?: { type?: string | undefined; limit?: number | undefined }): Promise<Envelope<ReadonlyArray<OrgAuditEvent>>> {
|
|
191
212
|
return request(config, { method: "GET", path: orgPath("audit-log"), query: opts });
|
|
192
213
|
},
|
|
193
|
-
|
|
194
|
-
/** Convenience: recent events (defaults to 5 minute window). */
|
|
195
|
-
async tail(opts?: { sinceMinutes?: number; limit?: number }): Promise<Envelope<ReadonlyArray<OrgAuditEvent>>> {
|
|
196
|
-
const minutes = opts?.sinceMinutes ?? 5;
|
|
197
|
-
const since = new Date(Date.now() - minutes * 60_000).toISOString();
|
|
198
|
-
return request(config, {
|
|
199
|
-
method: "GET",
|
|
200
|
-
path: orgPath("audit-log"),
|
|
201
|
-
query: { since, limit: opts?.limit ?? 100 },
|
|
202
|
-
});
|
|
203
|
-
},
|
|
204
214
|
};
|
|
205
215
|
}
|
|
206
216
|
|
|
207
217
|
function makeOrgGateNamespace(config: HttpClientConfig) {
|
|
208
218
|
return {
|
|
209
219
|
roles: {
|
|
210
|
-
/** GET /
|
|
211
|
-
async list(
|
|
212
|
-
return request(config, { method: "GET", path: orgPath("
|
|
220
|
+
/** GET /role-grants — list role grants. */
|
|
221
|
+
async list(): Promise<Envelope<ReadonlyArray<OrgRoleGrant>>> {
|
|
222
|
+
return request(config, { method: "GET", path: orgPath("role-grants") });
|
|
213
223
|
},
|
|
214
224
|
|
|
215
|
-
/** POST /
|
|
216
|
-
async grant(input: { userId: string; role: OrgRoleGrant["role"] }): Promise<Envelope<OrgRoleGrant>> {
|
|
217
|
-
return request(config, { method: "POST", path: orgPath("
|
|
225
|
+
/** POST /role-grants — grant an org role. */
|
|
226
|
+
async grant(input: { userId: string; role: OrgRoleGrant["role"]; decisionReason?: string | undefined }): Promise<Envelope<OrgRoleGrant>> {
|
|
227
|
+
return request(config, { method: "POST", path: orgPath("role-grants"), body: input });
|
|
218
228
|
},
|
|
219
229
|
|
|
220
|
-
/** GET /
|
|
230
|
+
/** GET /role-grants/<grantId> — single-read. */
|
|
221
231
|
async get(grantId: string): Promise<Envelope<OrgRoleGrant>> {
|
|
222
|
-
return request(config, { method: "GET", path: orgPath(`
|
|
232
|
+
return request(config, { method: "GET", path: orgPath(`role-grants/${encodeURIComponent(grantId)}`) });
|
|
223
233
|
},
|
|
224
234
|
|
|
225
|
-
/** DELETE /
|
|
226
|
-
async revoke(grantId: string): Promise<Envelope<OrgRoleGrant>> {
|
|
227
|
-
return request(config, { method: "DELETE", path: orgPath(`
|
|
235
|
+
/** DELETE /role-grants/<grantId> — revoke a grant (soft delete; sets revokedAt). */
|
|
236
|
+
async revoke(grantId: string, opts?: { decisionReason?: string | undefined }): Promise<Envelope<OrgRoleGrant>> {
|
|
237
|
+
return request(config, { method: "DELETE", path: orgPath(`role-grants/${encodeURIComponent(grantId)}`), ...(opts ? { body: opts } : {}) });
|
|
228
238
|
},
|
|
229
239
|
},
|
|
230
240
|
|
|
231
241
|
idpProviders: {
|
|
232
|
-
/** GET /
|
|
242
|
+
/** GET /identity-providers — list configured identity providers. */
|
|
233
243
|
async list(): Promise<Envelope<ReadonlyArray<OrgIdpProvider>>> {
|
|
234
|
-
return request(config, { method: "GET", path: orgPath("
|
|
244
|
+
return request(config, { method: "GET", path: orgPath("identity-providers") });
|
|
235
245
|
},
|
|
236
246
|
|
|
237
|
-
/** POST /
|
|
247
|
+
/** POST /identity-providers — create a new IdP integration. */
|
|
238
248
|
async create(input: CreateOrgIdpInput): Promise<Envelope<OrgIdpProvider>> {
|
|
239
|
-
return request(config, { method: "POST", path: orgPath("
|
|
249
|
+
return request(config, { method: "POST", path: orgPath("identity-providers"), body: input });
|
|
240
250
|
},
|
|
241
251
|
|
|
242
|
-
/** GET /
|
|
252
|
+
/** GET /identity-providers/<idpId>. */
|
|
243
253
|
async get(idpId: string): Promise<Envelope<OrgIdpProvider>> {
|
|
244
|
-
return request(config, { method: "GET", path: orgPath(`
|
|
254
|
+
return request(config, { method: "GET", path: orgPath(`identity-providers/${encodeURIComponent(idpId)}`) });
|
|
245
255
|
},
|
|
246
256
|
|
|
247
|
-
/** PATCH /
|
|
248
|
-
async configure(idpId: string, patch:
|
|
249
|
-
return request(config, { method: "PATCH", path: orgPath(`
|
|
257
|
+
/** PATCH /identity-providers/<idpId> — update settings or enable/disable. */
|
|
258
|
+
async configure(idpId: string, patch: UpdateOrgIdpInput): Promise<Envelope<OrgIdpProvider>> {
|
|
259
|
+
return request(config, { method: "PATCH", path: orgPath(`identity-providers/${encodeURIComponent(idpId)}`), body: patch });
|
|
250
260
|
},
|
|
251
261
|
|
|
252
|
-
/** DELETE /
|
|
262
|
+
/** DELETE /identity-providers/<idpId>. */
|
|
253
263
|
async delete(idpId: string): Promise<Envelope<{ deleted: boolean }>> {
|
|
254
|
-
return request(config, { method: "DELETE", path: orgPath(`
|
|
264
|
+
return request(config, { method: "DELETE", path: orgPath(`identity-providers/${encodeURIComponent(idpId)}`) });
|
|
255
265
|
},
|
|
256
266
|
},
|
|
257
267
|
};
|
|
@@ -260,21 +270,10 @@ function makeOrgGateNamespace(config: HttpClientConfig) {
|
|
|
260
270
|
function makeSmtpNamespace(config: HttpClientConfig) {
|
|
261
271
|
return {
|
|
262
272
|
/**
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
* platform SMTP 3-tier cascade).
|
|
266
|
-
*/
|
|
267
|
-
async get(): Promise<Envelope<SmtpConfig | null>> {
|
|
268
|
-
return request(config, { method: "GET", path: orgPath("org/smtp") });
|
|
269
|
-
},
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* PATCH /orgs/<orgSlug> with `smtpConfig` body — set or update SMTP.
|
|
273
|
-
* PATCH on the org resource accepts smtpConfig.
|
|
274
|
-
* Passwords route through Kibo enclave — SDK accepts plaintext at
|
|
275
|
-
* the SDK boundary; gateway stores the reference.
|
|
273
|
+
* PATCH /org with `smtpConfig` body — set or update SMTP. Answers the org record.
|
|
274
|
+
* The body carries `passwordRef` (a reference to the stored password), not the password.
|
|
276
275
|
*/
|
|
277
|
-
async set(config_:
|
|
276
|
+
async set(config_: SmtpConfig): Promise<Envelope<Org>> {
|
|
278
277
|
return request(config, { method: "PATCH", path: orgPath("org"), body: { smtpConfig: config_ } });
|
|
279
278
|
},
|
|
280
279
|
|
|
@@ -287,8 +286,8 @@ function makeSmtpNamespace(config: HttpClientConfig) {
|
|
|
287
286
|
return request(config, { method: "POST", path: orgPath("org/smtp/test-email"), body: input });
|
|
288
287
|
},
|
|
289
288
|
|
|
290
|
-
/** PATCH /
|
|
291
|
-
async unset(): Promise<Envelope<
|
|
289
|
+
/** PATCH /org with `smtpConfig: null` — clear org-level SMTP. Answers the org record. */
|
|
290
|
+
async unset(): Promise<Envelope<Org>> {
|
|
292
291
|
return request(config, { method: "PATCH", path: orgPath("org"), body: { smtpConfig: null } });
|
|
293
292
|
},
|
|
294
293
|
};
|
|
@@ -297,21 +296,20 @@ function makeSmtpNamespace(config: HttpClientConfig) {
|
|
|
297
296
|
function makeDefaultLlmNamespace(config: HttpClientConfig) {
|
|
298
297
|
return {
|
|
299
298
|
/**
|
|
300
|
-
* GET /
|
|
301
|
-
|
|
302
|
-
* falls back to `mistral-7b`). ORG_ADMIN read; tier-gated.
|
|
299
|
+
* GET /default-llm — read the org-default LLM model id.
|
|
300
|
+
* Any accepted member of the org may read it.
|
|
303
301
|
*/
|
|
304
|
-
async get(): Promise<Envelope<
|
|
305
|
-
return request(config, { method: "GET", path: orgPath("
|
|
302
|
+
async get(): Promise<Envelope<OrgDefaultLlm>> {
|
|
303
|
+
return request(config, { method: "GET", path: orgPath("default-llm") });
|
|
306
304
|
},
|
|
307
305
|
|
|
308
306
|
/**
|
|
309
|
-
* PATCH /
|
|
310
|
-
* ORG_ADMIN only. The model must be available to the org's tier
|
|
307
|
+
* PATCH /default-llm — set the org-default LLM.
|
|
308
|
+
* ORG_ADMIN or ORG_OWNER only. The model must be available to the org's tier
|
|
311
309
|
* or the gateway returns K9O_TIER_FEATURE_GATED.
|
|
312
310
|
*/
|
|
313
|
-
async set(input: { modelId: LLMModelId }): Promise<Envelope<
|
|
314
|
-
return request(config, { method: "PATCH", path: orgPath("
|
|
311
|
+
async set(input: { modelId: LLMModelId }): Promise<Envelope<{ orgId: string; defaultModelId: string }>> {
|
|
312
|
+
return request(config, { method: "PATCH", path: orgPath("default-llm"), body: input });
|
|
315
313
|
},
|
|
316
314
|
};
|
|
317
315
|
}
|
|
@@ -322,25 +320,25 @@ function makeDefaultLlmNamespace(config: HttpClientConfig) {
|
|
|
322
320
|
|
|
323
321
|
export function makeOrgNamespace(config: HttpClientConfig) {
|
|
324
322
|
return {
|
|
325
|
-
/** Member lifecycle — list / invite /
|
|
323
|
+
/** Member lifecycle — list / invite / remove. */
|
|
326
324
|
members: makeMembersNamespace(config),
|
|
327
|
-
/**
|
|
325
|
+
/** Groups — list / get (read-only). */
|
|
328
326
|
groups: makeGroupsNamespace(config),
|
|
329
|
-
/** Org-plane audit log — query
|
|
327
|
+
/** Org-plane audit log — query. Distinct from project-plane `client.audit`. */
|
|
330
328
|
auditLog: makeOrgAuditLogNamespace(config),
|
|
331
329
|
/** Gate (IAK) org-level surfaces — role-grants + IdP-providers. */
|
|
332
330
|
gate: makeOrgGateNamespace(config),
|
|
333
|
-
/** Org-level SMTP config —
|
|
331
|
+
/** Org-level SMTP config — set / test / unset. */
|
|
334
332
|
smtp: makeSmtpNamespace(config),
|
|
335
333
|
/** Org-default LLM — get / set (ORG_ADMIN). */
|
|
336
334
|
defaultLLM: makeDefaultLlmNamespace(config),
|
|
337
335
|
|
|
338
336
|
/**
|
|
339
|
-
* GET /org — read the current org (slug
|
|
337
|
+
* GET /org — read the current org (slug, displayName, products, billing tier, your role).
|
|
340
338
|
* Mirrors `client.orgs.current()` for symmetry; `client.org.get()` is
|
|
341
339
|
* the singular-namespace convention for use within an org-bound client.
|
|
342
340
|
*/
|
|
343
|
-
async get(): Promise<Envelope<
|
|
341
|
+
async get(): Promise<Envelope<Org>> {
|
|
344
342
|
return request(config, { method: "GET", path: orgPath("org") });
|
|
345
343
|
},
|
|
346
344
|
};
|
package/src/orgs.ts
CHANGED
|
@@ -26,14 +26,27 @@ import { request, type HttpClientConfig } from "./http.ts";
|
|
|
26
26
|
import { orgPath, validateSlug } from "./url-grammar.ts";
|
|
27
27
|
import type { Envelope } from "./envelope.ts";
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Org record, as the gateway returns it. `list` rows add `viaToken` and `consoleDomain`;
|
|
31
|
+
* `get`, `current` and `restore` add `customDomain` and `deletedAt`.
|
|
32
|
+
*/
|
|
29
33
|
export type Org = {
|
|
30
34
|
/** `org_<base62>`. */
|
|
31
35
|
id: string;
|
|
32
36
|
slug: string;
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
displayName: string;
|
|
38
|
+
products: ReadonlyArray<string>;
|
|
39
|
+
billingTier: string;
|
|
40
|
+
signupProduct: string;
|
|
41
|
+
/** The caller's role in the org. */
|
|
42
|
+
role: string;
|
|
35
43
|
createdAt: string;
|
|
36
|
-
|
|
44
|
+
customDomain?: string | null | undefined;
|
|
45
|
+
deletedAt?: string | null | undefined;
|
|
46
|
+
/** List rows only: `true` when the org is reached through the token rather than a membership. */
|
|
47
|
+
viaToken?: boolean | undefined;
|
|
48
|
+
/** List rows only: the org's Console host. */
|
|
49
|
+
consoleDomain?: string | undefined;
|
|
37
50
|
};
|
|
38
51
|
|
|
39
52
|
export function makeOrgsNamespace(config: HttpClientConfig) {
|
package/src/policies.ts
CHANGED
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
* - `delete(bundleId)` → DELETE /@<slug>/policies/<id>
|
|
14
14
|
* - `publish(bundleId)` → POST /@<slug>/policies/<id>/publish
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
16
|
+
* Only authoring roles write policy and only custodian roles publish.
|
|
17
|
+
* `validate` is read-only and any role with policy-read can lint a
|
|
18
|
+
* candidate document.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import { request, type HttpClientConfig } from "./http.ts";
|
|
@@ -25,29 +25,63 @@ import type { Envelope } from "./envelope.ts";
|
|
|
25
25
|
export type PolicyBundle = {
|
|
26
26
|
/** `pol_<base62>`. */
|
|
27
27
|
id: string;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
projectId: string;
|
|
29
|
+
status: "draft" | "published" | "superseded";
|
|
30
|
+
/** The policy document. */
|
|
31
|
+
policy: PolicyDocument;
|
|
32
|
+
/** The rules catalogue, when the bundle carries one. */
|
|
33
|
+
rules?: unknown;
|
|
34
|
+
createdBy: string;
|
|
32
35
|
createdAt: string;
|
|
33
36
|
publishedAt: string | null;
|
|
34
|
-
|
|
37
|
+
supersededAt: string | null;
|
|
38
|
+
supersededBy: string | null;
|
|
39
|
+
source: "rest" | "migration" | "cli";
|
|
40
|
+
editorMode: "visual" | "json" | "unspecified";
|
|
41
|
+
supersededReason: string | null;
|
|
42
|
+
/** Id of a queued publish awaiting a second approver, else `null`. */
|
|
43
|
+
pendingChangeId: string | null;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/** Answer of `publish`: the publish is queued for approval (HTTP 202). */
|
|
47
|
+
export type PolicyPublishResult = {
|
|
48
|
+
pendingChangeId: string;
|
|
49
|
+
bundleId: string;
|
|
50
|
+
status: "pending_approval";
|
|
35
51
|
};
|
|
36
52
|
|
|
53
|
+
/**
|
|
54
|
+
* The policy document: sections keyed by resource kind (`collections`,
|
|
55
|
+
* `storage`, `tools`, `functions`, `secrets`, `streams`, `analytics`);
|
|
56
|
+
* other keys are allowed.
|
|
57
|
+
*/
|
|
58
|
+
export type PolicyDocument = Record<string, unknown>;
|
|
59
|
+
|
|
37
60
|
export type CreatePolicyInput = {
|
|
38
|
-
|
|
39
|
-
rules
|
|
61
|
+
policy: PolicyDocument;
|
|
62
|
+
rules?: unknown;
|
|
63
|
+
editorMode?: "visual" | "json" | "unspecified" | undefined;
|
|
40
64
|
};
|
|
41
65
|
|
|
42
66
|
export type UpdatePolicyInput = {
|
|
43
|
-
|
|
44
|
-
rules?:
|
|
67
|
+
policy: PolicyDocument;
|
|
68
|
+
rules?: unknown;
|
|
69
|
+
editorMode?: "visual" | "json" | "unspecified" | undefined;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export type ValidatePolicyInput = {
|
|
73
|
+
policy: PolicyDocument;
|
|
74
|
+
rules?: unknown;
|
|
45
75
|
};
|
|
46
76
|
|
|
77
|
+
/** Validation failures are errors, so a successful validate always answers `{ valid: true }`. */
|
|
47
78
|
export type ValidatePolicyResult = {
|
|
48
|
-
valid:
|
|
49
|
-
|
|
50
|
-
|
|
79
|
+
valid: true;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/** Optional publish controls; property names are the gateway's. */
|
|
83
|
+
export type PublishPolicyOptions = {
|
|
84
|
+
acknowledgeSelfLockout?: boolean | undefined;
|
|
51
85
|
};
|
|
52
86
|
|
|
53
87
|
function requireProjectSlug(config: HttpClientConfig): string {
|
|
@@ -68,8 +102,8 @@ export function makePoliciesNamespace(config: HttpClientConfig) {
|
|
|
68
102
|
});
|
|
69
103
|
},
|
|
70
104
|
|
|
71
|
-
/** List all policy bundles (draft + published +
|
|
72
|
-
async list(opts?: { status?: PolicyBundle["status"] | undefined
|
|
105
|
+
/** List all policy bundles (draft + published + superseded). */
|
|
106
|
+
async list(opts?: { status?: PolicyBundle["status"] | undefined }): Promise<Envelope<ReadonlyArray<PolicyBundle>>> {
|
|
73
107
|
const slug = requireProjectSlug(config);
|
|
74
108
|
return request(config, {
|
|
75
109
|
method: "GET",
|
|
@@ -88,8 +122,8 @@ export function makePoliciesNamespace(config: HttpClientConfig) {
|
|
|
88
122
|
});
|
|
89
123
|
},
|
|
90
124
|
|
|
91
|
-
/** Lint a candidate
|
|
92
|
-
async validate(input:
|
|
125
|
+
/** Lint a candidate policy document without persisting. */
|
|
126
|
+
async validate(input: ValidatePolicyInput): Promise<Envelope<ValidatePolicyResult>> {
|
|
93
127
|
const slug = requireProjectSlug(config);
|
|
94
128
|
return request(config, {
|
|
95
129
|
method: "POST",
|
|
@@ -107,7 +141,7 @@ export function makePoliciesNamespace(config: HttpClientConfig) {
|
|
|
107
141
|
});
|
|
108
142
|
},
|
|
109
143
|
|
|
110
|
-
/**
|
|
144
|
+
/** Replace a draft bundle's policy document. Cannot patch published bundles (publish→republish flow). */
|
|
111
145
|
async update(bundleId: string, patch: UpdatePolicyInput): Promise<Envelope<PolicyBundle>> {
|
|
112
146
|
const slug = requireProjectSlug(config);
|
|
113
147
|
return request(config, {
|
|
@@ -117,8 +151,8 @@ export function makePoliciesNamespace(config: HttpClientConfig) {
|
|
|
117
151
|
});
|
|
118
152
|
},
|
|
119
153
|
|
|
120
|
-
/** Delete a draft bundle. Cannot delete published bundles. */
|
|
121
|
-
async delete(bundleId: string): Promise<Envelope<
|
|
154
|
+
/** Delete a draft bundle. Cannot delete published bundles. The gateway answers 204 with no body. */
|
|
155
|
+
async delete(bundleId: string): Promise<Envelope<undefined>> {
|
|
122
156
|
const slug = requireProjectSlug(config);
|
|
123
157
|
return request(config, {
|
|
124
158
|
method: "DELETE",
|
|
@@ -126,12 +160,17 @@ export function makePoliciesNamespace(config: HttpClientConfig) {
|
|
|
126
160
|
});
|
|
127
161
|
},
|
|
128
162
|
|
|
129
|
-
/**
|
|
130
|
-
|
|
163
|
+
/**
|
|
164
|
+
* Publish a draft bundle. The gateway answers 202 with `{ pendingChangeId, bundleId }`: the publish waits for
|
|
165
|
+
* approval, then the bundle becomes active. Pass `acknowledgeSelfLockout: true` to proceed when the bundle
|
|
166
|
+
* would remove your own read access to a collection.
|
|
167
|
+
*/
|
|
168
|
+
async publish(bundleId: string, options?: PublishPolicyOptions): Promise<Envelope<PolicyPublishResult>> {
|
|
131
169
|
const slug = requireProjectSlug(config);
|
|
132
170
|
return request(config, {
|
|
133
171
|
method: "POST",
|
|
134
172
|
path: projectPath(slug, `policies/${encodeURIComponent(bundleId)}/publish`),
|
|
173
|
+
...(options !== undefined ? { body: options } : {}),
|
|
135
174
|
});
|
|
136
175
|
},
|
|
137
176
|
};
|