@kindgi/platform 0.0.0-bootstrap.0 → 0.1.1
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/LICENSE +201 -0
- package/README.md +41 -1
- package/dist/in-memory/index.d.ts +9 -0
- package/dist/in-memory/index.d.ts.map +1 -0
- package/dist/in-memory/index.js +11 -0
- package/dist/in-memory/index.js.map +1 -0
- package/dist/in-memory/org-binding.d.ts +6 -0
- package/dist/in-memory/org-binding.d.ts.map +1 -0
- package/dist/in-memory/org-binding.js +81 -0
- package/dist/in-memory/org-binding.js.map +1 -0
- package/dist/in-memory/project-binding.d.ts +13 -0
- package/dist/in-memory/project-binding.d.ts.map +1 -0
- package/dist/in-memory/project-binding.js +286 -0
- package/dist/in-memory/project-binding.js.map +1 -0
- package/dist/in-memory/team-binding.d.ts +12 -0
- package/dist/in-memory/team-binding.d.ts.map +1 -0
- package/dist/in-memory/team-binding.js +170 -0
- package/dist/in-memory/team-binding.js.map +1 -0
- package/dist/in-memory/util.d.ts +27 -0
- package/dist/in-memory/util.d.ts.map +1 -0
- package/dist/in-memory/util.js +49 -0
- package/dist/in-memory/util.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/org-binding.d.ts +70 -0
- package/dist/org-binding.d.ts.map +1 -0
- package/dist/org-binding.js +4 -0
- package/dist/org-binding.js.map +1 -0
- package/dist/project-binding.d.ts +115 -0
- package/dist/project-binding.d.ts.map +1 -0
- package/dist/project-binding.js +4 -0
- package/dist/project-binding.js.map +1 -0
- package/dist/scope.d.ts +45 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +13 -0
- package/dist/scope.js.map +1 -0
- package/dist/team-binding.d.ts +108 -0
- package/dist/team-binding.d.ts.map +1 -0
- package/dist/team-binding.js +4 -0
- package/dist/team-binding.js.map +1 -0
- package/dist/team-project-grant-binding.d.ts +49 -0
- package/dist/team-project-grant-binding.d.ts.map +1 -0
- package/dist/team-project-grant-binding.js +4 -0
- package/dist/team-project-grant-binding.js.map +1 -0
- package/dist/tenant-hierarchy-binding.d.ts +104 -0
- package/dist/tenant-hierarchy-binding.d.ts.map +1 -0
- package/dist/tenant-hierarchy-binding.js +4 -0
- package/dist/tenant-hierarchy-binding.js.map +1 -0
- package/dist/types.d.ts +129 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +49 -4
- package/src/in-memory/index.ts +12 -0
- package/src/in-memory/org-binding.ts +101 -0
- package/src/in-memory/project-binding.ts +327 -0
- package/src/in-memory/team-binding.ts +205 -0
- package/src/in-memory/util.ts +72 -0
- package/src/index.ts +56 -0
- package/src/org-binding.ts +76 -0
- package/src/project-binding.ts +134 -0
- package/src/scope.ts +51 -0
- package/src/team-binding.ts +116 -0
- package/src/team-project-grant-binding.ts +65 -0
- package/src/tenant-hierarchy-binding.ts +107 -0
- package/src/types.ts +177 -0
- package/tests/in-memory-org-binding.test.ts +12 -0
- package/tests/in-memory-project-binding.test.ts +12 -0
- package/tests/in-memory-team-binding.test.ts +12 -0
- package/tests/org-binding.conformance.ts +165 -0
- package/tests/project-binding.conformance.ts +231 -0
- package/tests/team-binding.conformance.ts +175 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `OrgBinding` — CRUD surface for the `Org` primitive within a tenant.
|
|
3
|
+
*
|
|
4
|
+
* Conventions shared by every binding in this package:
|
|
5
|
+
* - Every method takes `tenantId: TenantId` as its first argument. The
|
|
6
|
+
* binding is responsible for enforcing tenant isolation: a call from
|
|
7
|
+
* tenant A must never surface a row from tenant B.
|
|
8
|
+
* - `list` returns the shared `Page<T>` envelope from
|
|
9
|
+
* `@kindgi/types` (`items` + `nextCursor`).
|
|
10
|
+
* - `list` filters extend the shared `Filter` shape so every list call
|
|
11
|
+
* shares the same pagination fields.
|
|
12
|
+
*
|
|
13
|
+
* This package ships the interface + reference in-memory adapter
|
|
14
|
+
* (in `./in-memory/org-binding.ts`). Any adapter can be checked with
|
|
15
|
+
* the conformance suite in `packages/platform/tests/`
|
|
16
|
+
* (`runOrgBindingConformance`).
|
|
17
|
+
*/
|
|
18
|
+
import type { Filter, OrgId, Page, TenantId } from '@kindgi/types';
|
|
19
|
+
import type { Org, OrgPatch, OrgSpec } from './types.js';
|
|
20
|
+
/**
|
|
21
|
+
* `list` filter for orgs. Extends the shared `Filter` with `orgs`-
|
|
22
|
+
* specific facets. Every additional field on the list contract lives
|
|
23
|
+
* here (not on the method signature) so the shape survives SDK codegen
|
|
24
|
+
* unchanged.
|
|
25
|
+
*
|
|
26
|
+
* - `nameContains` — case-sensitive substring match on `Org.name`.
|
|
27
|
+
* Optional; absent = no name filter. The `@kindgi/api` orgs route
|
|
28
|
+
* exposes it as `?nameContains=`.
|
|
29
|
+
*/
|
|
30
|
+
export interface OrgListFilter extends Filter {
|
|
31
|
+
readonly nameContains?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The org CRUD binding. Framework consumers implement one of these
|
|
35
|
+
* per persistence backend (Postgres, in-memory for tests).
|
|
36
|
+
*/
|
|
37
|
+
export interface OrgBinding {
|
|
38
|
+
/**
|
|
39
|
+
* Create a new `Org` in the given tenant. Returns the freshly-
|
|
40
|
+
* assigned `OrgId`. The binding is responsible for allocating IDs,
|
|
41
|
+
* timestamps, and slug-uniqueness enforcement within the tenant.
|
|
42
|
+
*/
|
|
43
|
+
create(tenantId: TenantId, spec: OrgSpec): Promise<OrgId>;
|
|
44
|
+
/**
|
|
45
|
+
* Look up an `Org` by id. Returns `undefined` when no row exists in
|
|
46
|
+
* the given tenant, or when the row exists in a different tenant
|
|
47
|
+
* (tenant isolation is by construction, never a silent leak).
|
|
48
|
+
*/
|
|
49
|
+
get(tenantId: TenantId, orgId: OrgId): Promise<Org | undefined>;
|
|
50
|
+
/**
|
|
51
|
+
* Cursor-paginated list of orgs within a tenant. Uses the shared
|
|
52
|
+
* `Page<Org>` envelope from `@kindgi/types` — consumers loop on
|
|
53
|
+
* `nextCursor` until it's absent.
|
|
54
|
+
*/
|
|
55
|
+
list(tenantId: TenantId, filter: OrgListFilter): Promise<Page<Org>>;
|
|
56
|
+
/**
|
|
57
|
+
* Partially update an `Org`. Fields absent from `patch` are left
|
|
58
|
+
* unchanged; fields present are set to the new value. Not-found is
|
|
59
|
+
* an error the adapter surfaces (e.g. as a rejected promise); the
|
|
60
|
+
* conformance suite specifies the exact shape.
|
|
61
|
+
*/
|
|
62
|
+
update(tenantId: TenantId, orgId: OrgId, patch: OrgPatch): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Delete an `Org`. Cascade semantics (dependent teams / projects) are
|
|
65
|
+
* a storage-layer concern — the in-memory adapter does the delete
|
|
66
|
+
* unconditionally.
|
|
67
|
+
*/
|
|
68
|
+
delete(tenantId: TenantId, orgId: OrgId): Promise<void>;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=org-binding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-binding.d.ts","sourceRoot":"","sources":["../src/org-binding.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEnE,OAAO,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAEzD;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAc,SAAQ,MAAM;IAC3C,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB;;;;OAIG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1D;;;;OAIG;IACH,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC;IAChE;;;;OAIG;IACH,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACpE;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE;;;;OAIG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-binding.js","sourceRoot":"","sources":["../src/org-binding.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ProjectBinding` + `ProjectMembershipBinding` — the project CRUD
|
|
3
|
+
* surface + the user↔project direct-grant membership surface within a
|
|
4
|
+
* tenant.
|
|
5
|
+
*
|
|
6
|
+
* Projects are the primary content-scope; all content (memory /
|
|
7
|
+
* agents / flows / guardrails / runs / artifacts / cost / evals /
|
|
8
|
+
* approvals / evidence / provenance / observations) carries a
|
|
9
|
+
* required `projectId` and is read/written filtered by it.
|
|
10
|
+
*
|
|
11
|
+
* `getDefault` returns the tenant's auto-created "Default" project.
|
|
12
|
+
* That row is the only one where `Project.isDefault = true`;
|
|
13
|
+
* implementations keep exactly one per tenant (this binding's
|
|
14
|
+
* in-memory adapter checks at write time, before the row lands in the
|
|
15
|
+
* map). Callers that don't naturally know a project resolve the
|
|
16
|
+
* Default with `getDefault` and pass its id explicitly (see e.g.
|
|
17
|
+
* `AgentPublishInput.projectId` in `@kindgi/api`).
|
|
18
|
+
*
|
|
19
|
+
* Same convention as `org-binding.ts`: `tenantId` first, `Page<T>`
|
|
20
|
+
* return, `Filter`-extending filter shapes.
|
|
21
|
+
*/
|
|
22
|
+
import type { Filter, OrgId, Page, ProjectId, TenantId, UserId } from '@kindgi/types';
|
|
23
|
+
import type { Project, ProjectMembership, ProjectPatch, ProjectRole, ProjectSpec } from './types.js';
|
|
24
|
+
/**
|
|
25
|
+
* `list` filter for projects. Same shape as `TeamListFilter` — `orgId`
|
|
26
|
+
* narrows to a specific org's projects (nullable FK);
|
|
27
|
+
* `nameContains` is a substring match on `Project.name`.
|
|
28
|
+
*/
|
|
29
|
+
export interface ProjectListFilter extends Filter {
|
|
30
|
+
readonly orgId?: OrgId;
|
|
31
|
+
readonly nameContains?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Input for `ProjectMembershipBinding.add`. Distinct interface so
|
|
35
|
+
* downstream additions extend without breaking call sites.
|
|
36
|
+
*/
|
|
37
|
+
export interface ProjectMembershipAddInput {
|
|
38
|
+
readonly projectId: ProjectId;
|
|
39
|
+
readonly userId: UserId;
|
|
40
|
+
readonly role: ProjectRole;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The project CRUD binding.
|
|
44
|
+
*/
|
|
45
|
+
export interface ProjectBinding {
|
|
46
|
+
/**
|
|
47
|
+
* Create a `Project` within the tenant. `spec.orgId` optional. If
|
|
48
|
+
* `spec.isDefault === true` and a Default already exists, the
|
|
49
|
+
* binding rejects — the isDefault-uniqueness guardrail is enforced
|
|
50
|
+
* at write time.
|
|
51
|
+
*/
|
|
52
|
+
create(tenantId: TenantId, spec: ProjectSpec): Promise<ProjectId>;
|
|
53
|
+
/**
|
|
54
|
+
* Look up a `Project` by id. `undefined` when unknown or in a
|
|
55
|
+
* different tenant.
|
|
56
|
+
*/
|
|
57
|
+
get(tenantId: TenantId, projectId: ProjectId): Promise<Project | undefined>;
|
|
58
|
+
/**
|
|
59
|
+
* Cursor-paginated list of projects. Filter by `orgId` or
|
|
60
|
+
* `nameContains`.
|
|
61
|
+
*/
|
|
62
|
+
list(tenantId: TenantId, filter: ProjectListFilter): Promise<Page<Project>>;
|
|
63
|
+
/**
|
|
64
|
+
* The tenant's Default project (`isDefault: true`). Returns
|
|
65
|
+
* `undefined` when no Default project exists for the tenant.
|
|
66
|
+
*/
|
|
67
|
+
getDefault(tenantId: TenantId): Promise<Project | undefined>;
|
|
68
|
+
/**
|
|
69
|
+
* Partially update a `Project`. `ProjectPatch.orgId` supports
|
|
70
|
+
* `null` to re-assign the project out of any org.
|
|
71
|
+
*/
|
|
72
|
+
update(tenantId: TenantId, projectId: ProjectId, patch: ProjectPatch): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Delete a `Project`. What happens to content rows that still
|
|
75
|
+
* reference the project is the storage layer's concern; the
|
|
76
|
+
* in-memory adapter removes the project's direct memberships and
|
|
77
|
+
* team grants with it.
|
|
78
|
+
*/
|
|
79
|
+
delete(tenantId: TenantId, projectId: ProjectId): Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* User↔project direct-grant membership. Additive with team grants
|
|
83
|
+
* (the union rules); a user may have both a direct
|
|
84
|
+
* `ProjectMembership` and access via a team-project grant.
|
|
85
|
+
* Authorization resolves the union.
|
|
86
|
+
*/
|
|
87
|
+
export interface ProjectMembershipBinding {
|
|
88
|
+
/**
|
|
89
|
+
* Add a user directly to a project. Idempotent on
|
|
90
|
+
* `(projectId, userId)` — re-adding the same user does not mutate
|
|
91
|
+
* a stored differing role. Use `updateRole` to change roles.
|
|
92
|
+
*/
|
|
93
|
+
add(tenantId: TenantId, input: ProjectMembershipAddInput): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Remove the direct project grant. No-op when absent.
|
|
96
|
+
*/
|
|
97
|
+
remove(tenantId: TenantId, projectId: ProjectId, userId: UserId): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Cursor-paginated direct memberships of a project. Ordered by
|
|
100
|
+
* `joinedAt` ascending.
|
|
101
|
+
*/
|
|
102
|
+
list(tenantId: TenantId, projectId: ProjectId, filter: Filter): Promise<Page<ProjectMembership>>;
|
|
103
|
+
/**
|
|
104
|
+
* Cursor-paginated direct memberships of a user (across every
|
|
105
|
+
* project the user is directly a member of within the tenant).
|
|
106
|
+
* Used to resolve a user's direct project set.
|
|
107
|
+
*/
|
|
108
|
+
listForUser(tenantId: TenantId, userId: UserId, filter: Filter): Promise<Page<ProjectMembership>>;
|
|
109
|
+
/**
|
|
110
|
+
* Update an existing direct-membership's role. Errors when the
|
|
111
|
+
* membership doesn't exist.
|
|
112
|
+
*/
|
|
113
|
+
updateRole(tenantId: TenantId, projectId: ProjectId, userId: UserId, role: ProjectRole): Promise<void>;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=project-binding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-binding.d.ts","sourceRoot":"","sources":["../src/project-binding.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEtF,OAAO,KAAK,EACV,OAAO,EACP,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB;;;;GAIG;AACH,MAAM,WAAW,iBAAkB,SAAQ,MAAM;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAClE;;;OAGG;IACH,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IAC5E;;;OAGG;IACH,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5E;;;OAGG;IACH,UAAU,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;IAC7D;;;OAGG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrF;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjE;AAED;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE;;OAEG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF;;;OAGG;IACH,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACjG;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAClG;;;OAGG;IACH,UAAU,CACR,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-binding.js","sourceRoot":"","sources":["../src/project-binding.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC"}
|
package/dist/scope.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `Scope` primitive — a required, discriminated access boundary.
|
|
3
|
+
*
|
|
4
|
+
* Design decision: a subset of framework resources —
|
|
5
|
+
* those that describe policy, configuration, or authoring templates
|
|
6
|
+
* rather than run-time content — carry a required, discriminated
|
|
7
|
+
* `Scope` value that names the level at which the resource is
|
|
8
|
+
* visible. The `Scope` is not a filter; it's a **row-level property**
|
|
9
|
+
* recorded at insert time.
|
|
10
|
+
*
|
|
11
|
+
* Which resources carry `Scope` (vs `projectId`)?
|
|
12
|
+
* - **Content-scoped** (agents, flows, tools, guardrails, memory
|
|
13
|
+
* facts, artifacts, runs, cost records, eval suites, eval runs,
|
|
14
|
+
* approvals, evidence, provenance, observations): a required
|
|
15
|
+
* `projectId`. Rows are the *contents* of a project.
|
|
16
|
+
* - **Policy/config-scoped** (MCP endpoints, secrets, env values,
|
|
17
|
+
* pack templates, S3 credentials): `Scope` discriminated
|
|
18
|
+
* (Tenant / Org / Project). Describes *how* content is served —
|
|
19
|
+
* auth providers, credentials, template catalogs. A firm may want
|
|
20
|
+
* firm-wide MCP endpoints OR matter-scoped MCP endpoints; fixed to
|
|
21
|
+
* one level is wrong, nullable is worse.
|
|
22
|
+
* - **Tenant-only** (adapters, capabilities, identity providers,
|
|
23
|
+
* deployment ledger, signing keys, tenant config): a required
|
|
24
|
+
* `tenantId` only. Deployment-wide framework configuration.
|
|
25
|
+
*
|
|
26
|
+
* Resolution semantics (most-specific-wins): for a resource lookup
|
|
27
|
+
* within a request context that carries `{ tenantId, projectId }`,
|
|
28
|
+
* walk `project → org → tenant` (the org is the project's `orgId`);
|
|
29
|
+
* first match wins.
|
|
30
|
+
*/
|
|
31
|
+
import type { OrgId, ProjectId, TenantId } from '@kindgi/types';
|
|
32
|
+
export type Scope = {
|
|
33
|
+
readonly kind: 'tenant';
|
|
34
|
+
readonly tenantId: TenantId;
|
|
35
|
+
} | {
|
|
36
|
+
readonly kind: 'org';
|
|
37
|
+
readonly tenantId: TenantId;
|
|
38
|
+
readonly orgId: OrgId;
|
|
39
|
+
} | {
|
|
40
|
+
readonly kind: 'project';
|
|
41
|
+
readonly tenantId: TenantId;
|
|
42
|
+
readonly projectId: ProjectId;
|
|
43
|
+
};
|
|
44
|
+
export declare function scopeKey(s: Scope): string;
|
|
45
|
+
//# sourceMappingURL=scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEhE,MAAM,MAAM,KAAK,GACb;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GACxD;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAC5E;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAA;CAAE,CAAC;AAE7F,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CASzC"}
|
package/dist/scope.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright (C) 2026 Kindgi Inc.
|
|
3
|
+
export function scopeKey(s) {
|
|
4
|
+
switch (s.kind) {
|
|
5
|
+
case 'tenant':
|
|
6
|
+
return `tenant:${s.tenantId}`;
|
|
7
|
+
case 'org':
|
|
8
|
+
return `org:${s.orgId}`;
|
|
9
|
+
case 'project':
|
|
10
|
+
return `project:${s.projectId}`;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAwCjC,MAAM,UAAU,QAAQ,CAAC,CAAQ;IAC/B,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,QAAQ;YACX,OAAO,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC;QAChC,KAAK,KAAK;YACR,OAAO,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC;QAC1B,KAAK,SAAS;YACZ,OAAO,WAAW,CAAC,CAAC,SAAS,EAAE,CAAC;IACpC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `TeamBinding` + `TeamMembershipBinding` — the team CRUD surface + the
|
|
3
|
+
* user↔team membership surface within a tenant.
|
|
4
|
+
*
|
|
5
|
+
* Team memberships are **framework-owned**: there is no external
|
|
6
|
+
* directory sync. `TeamMembershipBinding` is the sole source of
|
|
7
|
+
* truth.
|
|
8
|
+
*
|
|
9
|
+
* Same convention as `org-binding.ts`: `tenantId` first, `Page<T>`
|
|
10
|
+
* return, `Filter`-extending filter shapes.
|
|
11
|
+
*/
|
|
12
|
+
import type { Filter, OrgId, Page, TeamId, TenantId, UserId } from '@kindgi/types';
|
|
13
|
+
import type { Team, TeamMembership, TeamPatch, TeamRole, TeamSpec } from './types.js';
|
|
14
|
+
/**
|
|
15
|
+
* `list` filter for teams. `orgId` narrows to teams belonging to a
|
|
16
|
+
* specific org (the `Team.orgId?` nullable FK); absent =
|
|
17
|
+
* no org filter, including cross-org teams. `nameContains` mirrors
|
|
18
|
+
* the org shape.
|
|
19
|
+
*/
|
|
20
|
+
export interface TeamListFilter extends Filter {
|
|
21
|
+
readonly orgId?: OrgId;
|
|
22
|
+
readonly nameContains?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Input for `TeamMembershipBinding.add`. Distinct interface (not
|
|
26
|
+
* positional args) so downstream additions — e.g., an `addedBy?:
|
|
27
|
+
* UserId` audit field added later — extend without breaking
|
|
28
|
+
* every call site.
|
|
29
|
+
*/
|
|
30
|
+
export interface TeamMembershipAddInput {
|
|
31
|
+
readonly teamId: TeamId;
|
|
32
|
+
readonly userId: UserId;
|
|
33
|
+
readonly role: TeamRole;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The team CRUD binding.
|
|
37
|
+
*/
|
|
38
|
+
export interface TeamBinding {
|
|
39
|
+
/**
|
|
40
|
+
* Create a `Team` within the tenant. `spec.orgId` optional (a team
|
|
41
|
+
* may be cross-org — nullable FK). Returns the assigned
|
|
42
|
+
* `TeamId`.
|
|
43
|
+
*/
|
|
44
|
+
create(tenantId: TenantId, spec: TeamSpec): Promise<TeamId>;
|
|
45
|
+
/**
|
|
46
|
+
* Look up a `Team` by id. `undefined` when unknown or in a different
|
|
47
|
+
* tenant.
|
|
48
|
+
*/
|
|
49
|
+
get(tenantId: TenantId, teamId: TeamId): Promise<Team | undefined>;
|
|
50
|
+
/**
|
|
51
|
+
* Cursor-paginated list of teams. Filter by `orgId` (narrow to one
|
|
52
|
+
* org's teams) or `nameContains` (substring match on `Team.name`).
|
|
53
|
+
*/
|
|
54
|
+
list(tenantId: TenantId, filter: TeamListFilter): Promise<Page<Team>>;
|
|
55
|
+
/**
|
|
56
|
+
* Partially update a `Team`. `TeamPatch.orgId` supports `null` to
|
|
57
|
+
* explicitly re-assign the team out of any org (cross-org), and
|
|
58
|
+
* `undefined` to leave the FK untouched.
|
|
59
|
+
*/
|
|
60
|
+
update(tenantId: TenantId, teamId: TeamId, patch: TeamPatch): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Delete a `Team`. Its membership rows are removed with it (the
|
|
63
|
+
* in-memory adapter deletes them from its map).
|
|
64
|
+
*/
|
|
65
|
+
delete(tenantId: TenantId, teamId: TeamId): Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* User↔team membership CRUD. Typical consumers: identity views that
|
|
69
|
+
* show a user's teams, and authorization, where the `team:T#member`
|
|
70
|
+
* userset (see `@kindgi/authz`) gives members access to projects
|
|
71
|
+
* through a team-project grant.
|
|
72
|
+
*/
|
|
73
|
+
export interface TeamMembershipBinding {
|
|
74
|
+
/**
|
|
75
|
+
* Add a user to a team with a given role. Idempotent on the
|
|
76
|
+
* `(teamId, userId)` primary key — re-adding the same user does not
|
|
77
|
+
* duplicate the row. To change an existing member's role use
|
|
78
|
+
* `updateRole` (semantics are explicit; add-with-role does not
|
|
79
|
+
* silently mutate a differing role).
|
|
80
|
+
*
|
|
81
|
+
* The conformance suite pins this: adding an existing member whose
|
|
82
|
+
* stored role differs is a no-op (not a role overwrite).
|
|
83
|
+
*/
|
|
84
|
+
add(tenantId: TenantId, input: TeamMembershipAddInput): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Remove a user from a team. Missing membership is a no-op (not an
|
|
87
|
+
* error) — matches every peer platform's membership-remove shape.
|
|
88
|
+
*/
|
|
89
|
+
remove(tenantId: TenantId, teamId: TeamId, userId: UserId): Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Cursor-paginated memberships of a team. Ordered by `joinedAt`
|
|
92
|
+
* ascending; the conformance suite pins this ordering.
|
|
93
|
+
*/
|
|
94
|
+
list(tenantId: TenantId, teamId: TeamId, filter: Filter): Promise<Page<TeamMembership>>;
|
|
95
|
+
/**
|
|
96
|
+
* Cursor-paginated memberships of a user (across every team the
|
|
97
|
+
* user belongs to within the tenant). Used to resolve a user's team
|
|
98
|
+
* set (identity views, authorization inheritance).
|
|
99
|
+
*/
|
|
100
|
+
listForUser(tenantId: TenantId, userId: UserId, filter: Filter): Promise<Page<TeamMembership>>;
|
|
101
|
+
/**
|
|
102
|
+
* Update an existing membership's role. Errors when the membership
|
|
103
|
+
* doesn't exist — role mutation of a non-member is a caller mistake,
|
|
104
|
+
* not a silent add. Conformance suite pins the not-found behaviour.
|
|
105
|
+
*/
|
|
106
|
+
updateRole(tenantId: TenantId, teamId: TeamId, userId: UserId, role: TeamRole): Promise<void>;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=team-binding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-binding.d.ts","sourceRoot":"","sources":["../src/team-binding.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEnF,OAAO,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtF;;;;;GAKG;AACH,MAAM,WAAW,cAAe,SAAQ,MAAM;IAC5C,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;GAKG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5D;;;OAGG;IACH,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;IACnE;;;OAGG;IACH,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACtE;;;;OAIG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E;;;OAGG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3D;AAED;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;;;;;OASG;IACH,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtE;;;OAGG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E;;;OAGG;IACH,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;IACxF;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;IAC/F;;;;OAIG;IACH,UAAU,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/F"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-binding.js","sourceRoot":"","sources":["../src/team-binding.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `TeamProjectGrant` — the team↔project join surface. One row per
|
|
3
|
+
* `(teamId, projectId)` primary key; the `role` names the project-
|
|
4
|
+
* scope grant every team member inherits via the FGA `team:T#member`
|
|
5
|
+
* userset (see `@kindgi/authz`).
|
|
6
|
+
*
|
|
7
|
+
* Same tenant-first convention as every other binding in
|
|
8
|
+
* `@kindgi/platform`. The in-memory reference implementation is part
|
|
9
|
+
* of `makeInMemoryProjectBinding` (its `grants` binding).
|
|
10
|
+
*/
|
|
11
|
+
import type { Filter, Page, ProjectId, TeamId, TenantId } from '@kindgi/types';
|
|
12
|
+
import type { ProjectRole } from './types.js';
|
|
13
|
+
/**
|
|
14
|
+
* A team-mediated grant on a project. The `role` uses the same
|
|
15
|
+
* `ProjectRole` union as direct `ProjectMembership.role` — semantics
|
|
16
|
+
* compose (the authorization model resolves the union / inheritance).
|
|
17
|
+
*/
|
|
18
|
+
export interface TeamProjectGrant {
|
|
19
|
+
readonly teamId: TeamId;
|
|
20
|
+
readonly projectId: ProjectId;
|
|
21
|
+
readonly role: ProjectRole;
|
|
22
|
+
}
|
|
23
|
+
export interface TeamProjectGrantAddInput {
|
|
24
|
+
readonly teamId: TeamId;
|
|
25
|
+
readonly projectId: ProjectId;
|
|
26
|
+
readonly role: ProjectRole;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* CRUD for team↔project grants.
|
|
30
|
+
*/
|
|
31
|
+
export interface TeamProjectGrantBinding {
|
|
32
|
+
/**
|
|
33
|
+
* Add a team-project grant. Idempotent on `(teamId, projectId)` —
|
|
34
|
+
* re-adding the same team on the same project does not mutate a
|
|
35
|
+
* stored differing role. Use `updateRole` to change roles.
|
|
36
|
+
*/
|
|
37
|
+
add(tenantId: TenantId, input: TeamProjectGrantAddInput): Promise<void>;
|
|
38
|
+
/** Remove a team-project grant. No-op when absent. */
|
|
39
|
+
remove(tenantId: TenantId, teamId: TeamId, projectId: ProjectId): Promise<void>;
|
|
40
|
+
/** Cursor-paginated grants filtered by tenant. */
|
|
41
|
+
list(tenantId: TenantId, filter: Filter): Promise<Page<TeamProjectGrant>>;
|
|
42
|
+
/** Cursor-paginated grants for a specific team. */
|
|
43
|
+
listForTeam(tenantId: TenantId, teamId: TeamId, filter: Filter): Promise<Page<TeamProjectGrant>>;
|
|
44
|
+
/** Cursor-paginated grants for a specific project. */
|
|
45
|
+
listForProject(tenantId: TenantId, projectId: ProjectId, filter: Filter): Promise<Page<TeamProjectGrant>>;
|
|
46
|
+
/** Update a grant's role. Errors when the grant doesn't exist. */
|
|
47
|
+
updateRole(tenantId: TenantId, teamId: TeamId, projectId: ProjectId, role: ProjectRole): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=team-project-grant-binding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-project-grant-binding.d.ts","sourceRoot":"","sources":["../src/team-project-grant-binding.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE/E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;CAC5B;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxE,sDAAsD;IACtD,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,kDAAkD;IAClD,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC1E,mDAAmD;IACnD,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACjG,sDAAsD;IACtD,cAAc,CACZ,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACnC,kEAAkE;IAClE,UAAU,CACR,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team-project-grant-binding.js","sourceRoot":"","sources":["../src/team-project-grant-binding.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { OrgId, ProjectId, Result, TeamId, TenantId, UserId } from '@kindgi/types';
|
|
2
|
+
import type { OrgSpec, ProjectRole, ProjectSpec, TeamRole, TeamSpec } from './types.js';
|
|
3
|
+
export interface CreateOrgParams {
|
|
4
|
+
readonly tenantId: TenantId;
|
|
5
|
+
readonly creatorUserId: UserId;
|
|
6
|
+
readonly spec: OrgSpec;
|
|
7
|
+
}
|
|
8
|
+
export type CreateOrgError = {
|
|
9
|
+
readonly code: 'slug-conflict';
|
|
10
|
+
readonly message: string;
|
|
11
|
+
readonly cause?: unknown;
|
|
12
|
+
} | {
|
|
13
|
+
readonly code: 'insert-failed';
|
|
14
|
+
readonly message: string;
|
|
15
|
+
readonly cause?: unknown;
|
|
16
|
+
};
|
|
17
|
+
export interface CreateTeamParams {
|
|
18
|
+
readonly tenantId: TenantId;
|
|
19
|
+
readonly creatorUserId: UserId;
|
|
20
|
+
readonly spec: TeamSpec;
|
|
21
|
+
}
|
|
22
|
+
export type CreateTeamError = {
|
|
23
|
+
readonly code: 'slug-conflict';
|
|
24
|
+
readonly message: string;
|
|
25
|
+
readonly cause?: unknown;
|
|
26
|
+
} | {
|
|
27
|
+
readonly code: 'insert-failed';
|
|
28
|
+
readonly message: string;
|
|
29
|
+
readonly cause?: unknown;
|
|
30
|
+
};
|
|
31
|
+
export interface AddTeamMemberParams {
|
|
32
|
+
readonly tenantId: TenantId;
|
|
33
|
+
readonly teamId: TeamId;
|
|
34
|
+
readonly userId: UserId;
|
|
35
|
+
readonly role: TeamRole;
|
|
36
|
+
}
|
|
37
|
+
export interface CreateProjectParams {
|
|
38
|
+
readonly tenantId: TenantId;
|
|
39
|
+
readonly creatorUserId: UserId;
|
|
40
|
+
readonly spec: ProjectSpec;
|
|
41
|
+
}
|
|
42
|
+
export type CreateProjectError = {
|
|
43
|
+
readonly code: 'slug-conflict';
|
|
44
|
+
readonly message: string;
|
|
45
|
+
readonly cause?: unknown;
|
|
46
|
+
} | {
|
|
47
|
+
readonly code: 'default-conflict';
|
|
48
|
+
readonly message: string;
|
|
49
|
+
readonly cause?: unknown;
|
|
50
|
+
} | {
|
|
51
|
+
readonly code: 'insert-failed';
|
|
52
|
+
readonly message: string;
|
|
53
|
+
readonly cause?: unknown;
|
|
54
|
+
};
|
|
55
|
+
export interface AddProjectMemberParams {
|
|
56
|
+
readonly tenantId: TenantId;
|
|
57
|
+
readonly projectId: ProjectId;
|
|
58
|
+
readonly userId: UserId;
|
|
59
|
+
readonly role: ProjectRole;
|
|
60
|
+
}
|
|
61
|
+
export interface MembershipMutationError {
|
|
62
|
+
readonly code: string;
|
|
63
|
+
readonly message: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Tenant-summary read shape returned by `getTenant`. Only the fields
|
|
67
|
+
* the `/v1/tenant` GET route surfaces — id / name / slug / createdAt /
|
|
68
|
+
* updatedAt. Timestamps are ISO 8601 strings; impls that hold Date
|
|
69
|
+
* objects convert at the boundary.
|
|
70
|
+
*/
|
|
71
|
+
export interface TenantSummary {
|
|
72
|
+
readonly id: TenantId;
|
|
73
|
+
readonly name: string;
|
|
74
|
+
readonly slug: string;
|
|
75
|
+
readonly createdAt: string;
|
|
76
|
+
readonly updatedAt: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Tenant-hierarchy CRUD binding. Every route that creates orgs /
|
|
80
|
+
* teams / projects or adds members writes atomically: entity insert
|
|
81
|
+
* + FGA parent/owner tuples in the same transaction.
|
|
82
|
+
*
|
|
83
|
+
* Deployments supply the implementation; tests can substitute a mock.
|
|
84
|
+
*/
|
|
85
|
+
export interface TenantHierarchyBinding {
|
|
86
|
+
createOrg(params: CreateOrgParams): Promise<Result<{
|
|
87
|
+
readonly orgId: OrgId;
|
|
88
|
+
}, CreateOrgError>>;
|
|
89
|
+
createTeam(params: CreateTeamParams): Promise<Result<{
|
|
90
|
+
readonly teamId: TeamId;
|
|
91
|
+
}, CreateTeamError>>;
|
|
92
|
+
createProject(params: CreateProjectParams): Promise<Result<{
|
|
93
|
+
readonly projectId: ProjectId;
|
|
94
|
+
}, CreateProjectError>>;
|
|
95
|
+
addTeamMember(params: AddTeamMemberParams): Promise<Result<void, MembershipMutationError>>;
|
|
96
|
+
addProjectMember(params: AddProjectMemberParams): Promise<Result<void, MembershipMutationError>>;
|
|
97
|
+
/**
|
|
98
|
+
* Look up a tenant by id. Returns `null` when no tenant exists.
|
|
99
|
+
* Not itself tenant-scoped: it is how a caller finds out which
|
|
100
|
+
* tenant it is operating as.
|
|
101
|
+
*/
|
|
102
|
+
getTenant(tenantId: TenantId): Promise<TenantSummary | null>;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=tenant-hierarchy-binding.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant-hierarchy-binding.d.ts","sourceRoot":"","sources":["../src/tenant-hierarchy-binding.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant-hierarchy-binding.js","sourceRoot":"","sources":["../src/tenant-hierarchy-binding.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC"}
|