@astram/frontend-core 0.2.0 → 0.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/dist/auth/authService.d.ts +21 -0
- package/dist/auth/authService.d.ts.map +1 -1
- package/dist/auth/authService.js +14 -1
- package/dist/auth/authService.js.map +1 -1
- package/dist/auth/index.d.ts +4 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +2 -0
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/recordPolicyService.d.ts +101 -0
- package/dist/auth/recordPolicyService.d.ts.map +1 -0
- package/dist/auth/recordPolicyService.js +70 -0
- package/dist/auth/recordPolicyService.js.map +1 -0
- package/dist/auth/recordShareService.d.ts +60 -0
- package/dist/auth/recordShareService.d.ts.map +1 -0
- package/dist/auth/recordShareService.js +54 -0
- package/dist/auth/recordShareService.js.map +1 -0
- package/package.json +1 -1
|
@@ -34,10 +34,30 @@ export interface AuthProfile {
|
|
|
34
34
|
}>;
|
|
35
35
|
[key: string]: unknown;
|
|
36
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* The caller's own coarse auth-facts projection, as inlined into a login/mfa success
|
|
39
|
+
* body by the framework (same shape as `GET /identity/auth-facts`). ADDITIVE +
|
|
40
|
+
* OPTIONAL: present only when the server inlines it; the consumer seeds its
|
|
41
|
+
* permission-gated nav from this immediately, falling back to a separate auth-facts
|
|
42
|
+
* fetch when it is absent. Carries `permissionsVersion` so the SDK's version-staleness
|
|
43
|
+
* contract still holds.
|
|
44
|
+
*/
|
|
45
|
+
export interface AuthFactsProjection {
|
|
46
|
+
principalId: string;
|
|
47
|
+
facts: Array<{
|
|
48
|
+
action: string;
|
|
49
|
+
allowed: boolean;
|
|
50
|
+
resource?: string;
|
|
51
|
+
reasonCode?: string;
|
|
52
|
+
}>;
|
|
53
|
+
projectedAt: number;
|
|
54
|
+
permissionsVersion?: number;
|
|
55
|
+
}
|
|
37
56
|
export type LoginResult = {
|
|
38
57
|
ok: true;
|
|
39
58
|
session: Session;
|
|
40
59
|
tokens: SessionTokens;
|
|
60
|
+
authFacts?: AuthFactsProjection;
|
|
41
61
|
} | {
|
|
42
62
|
ok: 'mfa';
|
|
43
63
|
challengeToken: string;
|
|
@@ -50,6 +70,7 @@ export type CompleteMfaResult = {
|
|
|
50
70
|
session: Session;
|
|
51
71
|
tokens: SessionTokens;
|
|
52
72
|
mfaRecoveryUsed: boolean;
|
|
73
|
+
authFacts?: AuthFactsProjection;
|
|
53
74
|
} | {
|
|
54
75
|
ok: false;
|
|
55
76
|
error: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authService.d.ts","sourceRoot":"","sources":["../../src/auth/authService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE3D,2DAA2D;AAC3D,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;
|
|
1
|
+
{"version":3,"file":"authService.d.ts","sourceRoot":"","sources":["../../src/auth/authService.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/authService.js
CHANGED
|
@@ -15,7 +15,16 @@ export function createAuthService(http) {
|
|
|
15
15
|
return { ok: 'mfa', challengeToken: data.challengeToken };
|
|
16
16
|
}
|
|
17
17
|
if (r.ok && data?.session && data?.tokens) {
|
|
18
|
-
|
|
18
|
+
// `authFacts` is inlined by the framework so the consumer can seed its
|
|
19
|
+
// permission-gated nav in ONE round-trip; absent on an older server (→ the
|
|
20
|
+
// consumer falls back to a separate `/identity/auth-facts` fetch). Spread so the
|
|
21
|
+
// key stays truly absent when the server didn't inline it (exactOptionalPropertyTypes).
|
|
22
|
+
return {
|
|
23
|
+
ok: true,
|
|
24
|
+
session: data.session,
|
|
25
|
+
tokens: data.tokens,
|
|
26
|
+
...(data.authFacts ? { authFacts: data.authFacts } : {}),
|
|
27
|
+
};
|
|
19
28
|
}
|
|
20
29
|
if (r.status === 401)
|
|
21
30
|
return { ok: false, error: 'Invalid username or password.' };
|
|
@@ -40,6 +49,10 @@ export function createAuthService(http) {
|
|
|
40
49
|
session: data.session,
|
|
41
50
|
tokens: data.tokens,
|
|
42
51
|
mfaRecoveryUsed: data.mfaRecoveryUsed === true,
|
|
52
|
+
// Inlined by the framework (same one-round-trip seeding as login); absent on
|
|
53
|
+
// an older server → the consumer falls back to a separate auth-facts fetch.
|
|
54
|
+
// Spread so the key stays truly absent (exactOptionalPropertyTypes).
|
|
55
|
+
...(data.authFacts ? { authFacts: data.authFacts } : {}),
|
|
43
56
|
};
|
|
44
57
|
}
|
|
45
58
|
return { ok: false, error: 'Incorrect or expired code.' };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authService.js","sourceRoot":"","sources":["../../src/auth/authService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"authService.js","sourceRoot":"","sources":["../../src/auth/authService.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -9,6 +9,10 @@ export { createAccountService } from './accountService.js';
|
|
|
9
9
|
export { createIdentityService } from './identityService.js';
|
|
10
10
|
export { createAuditService } from './auditService.js';
|
|
11
11
|
export { createCrossTenantService } from './crossTenantService.js';
|
|
12
|
+
export { createRecordPolicyService } from './recordPolicyService.js';
|
|
13
|
+
export type { RecordPolicyService, GuidedPolicy, PolicyCondition, PolicyOperator, PolicyRow, PolicyTypeSchema, PolicyFieldSchema, } from './recordPolicyService.js';
|
|
14
|
+
export { createRecordShareService } from './recordShareService.js';
|
|
15
|
+
export type { RecordShareService, ShareRequest, ShareView, ShareGranteeKind, } from './recordShareService.js';
|
|
12
16
|
export { isAuthenticated, accessTokenOf, tenantOf, principalOf } from './session.js';
|
|
13
17
|
export { isRestorablePath, encodeReturnPath, decodeReturnPath } from './returnPath.js';
|
|
14
18
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/auth/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,YAAY,EACV,mBAAmB,EACnB,YAAY,EACZ,eAAe,EACf,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,YAAY,EACV,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACT,gBAAgB,GACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/auth/index.js
CHANGED
|
@@ -9,6 +9,8 @@ export { createAccountService } from './accountService.js';
|
|
|
9
9
|
export { createIdentityService } from './identityService.js';
|
|
10
10
|
export { createAuditService } from './auditService.js';
|
|
11
11
|
export { createCrossTenantService } from './crossTenantService.js';
|
|
12
|
+
export { createRecordPolicyService } from './recordPolicyService.js';
|
|
13
|
+
export { createRecordShareService } from './recordShareService.js';
|
|
12
14
|
export { isAuthenticated, accessTokenOf, tenantOf, principalOf } from './session.js';
|
|
13
15
|
export { isRestorablePath, encodeReturnPath, decodeReturnPath } from './returnPath.js';
|
|
14
16
|
//# sourceMappingURL=index.js.map
|
package/dist/auth/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAUrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAOnE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createRecordPolicyService — platform-agnostic calls to the identity feature's GUIDED
|
|
3
|
+
* RULE-BUILDER surface (§9.1 / list-scoping engine Phase 5). Like {@link createCrossTenantService},
|
|
4
|
+
* it takes an injected HTTP client, carries no platform code (web + mobile share it), and passes
|
|
5
|
+
* the bearer token per call. Every method resolves to a plain result object (never throws):
|
|
6
|
+
* `{ ok:true, ... }` on success, `{ ok:false, status, error }` on any non-2xx (401 = not
|
|
7
|
+
* authenticated, 403 = denied, 400 = the server's message, 404 = not found, else generic).
|
|
8
|
+
*
|
|
9
|
+
* The server routes these hit (all `@Classified` on the `role` type — read/update):
|
|
10
|
+
* GET /identity/record-policies/schema?typeKey= (the builder's field/operator metadata)
|
|
11
|
+
* GET /identity/record-policies?typeKey= (this tenant's policies for a type)
|
|
12
|
+
* POST /identity/record-policies (author a GuidedPolicy)
|
|
13
|
+
* DELETE /identity/record-policies/:id (delete one)
|
|
14
|
+
*
|
|
15
|
+
* ⛔ The target TENANT is NEVER sent by the client — the server authors in the caller's own tenant
|
|
16
|
+
* (a body tenant is ignored). ⛔ NO raw expression is ever authored — a policy is a closed set of
|
|
17
|
+
* structured conditions (field + operator + value); the schema endpoint drives the builder's
|
|
18
|
+
* dropdowns so the client can only compose valid combinations, and the server re-validates.
|
|
19
|
+
*/
|
|
20
|
+
import type { HttpClient, AbortSignalLike } from '../http/types.js';
|
|
21
|
+
/** The closed operator vocabulary (mirrors the server's `PolicyOperator`). */
|
|
22
|
+
export type PolicyOperator = 'eq' | 'ne' | 'in' | 'not_in' | 'gt' | 'lt' | 'gte' | 'lte' | 'contains' | 'not_contains' | 'is_null' | 'is_not_null';
|
|
23
|
+
/** One structured condition of a guided policy (AND-composed with its siblings). */
|
|
24
|
+
export interface PolicyCondition {
|
|
25
|
+
readonly field: string;
|
|
26
|
+
readonly operator: PolicyOperator;
|
|
27
|
+
/** Absent for nullary operators (is_null/is_not_null); an array for in/not_in. */
|
|
28
|
+
readonly value?: unknown;
|
|
29
|
+
}
|
|
30
|
+
/** A guided policy authored via the builder — NO raw expression. */
|
|
31
|
+
export interface GuidedPolicy {
|
|
32
|
+
readonly typeKey: string;
|
|
33
|
+
readonly action: string;
|
|
34
|
+
readonly effect: 'allow' | 'deny';
|
|
35
|
+
readonly conditions: readonly PolicyCondition[];
|
|
36
|
+
}
|
|
37
|
+
/** A persisted policy row (id + the authored policy). `policyId` is the delete key, never shown. */
|
|
38
|
+
export interface PolicyRow {
|
|
39
|
+
readonly policyId: string;
|
|
40
|
+
readonly tenantId: string;
|
|
41
|
+
readonly policy: GuidedPolicy;
|
|
42
|
+
}
|
|
43
|
+
/** One authorable field + the operators the builder should OFFER for it. */
|
|
44
|
+
export interface PolicyFieldSchema {
|
|
45
|
+
readonly key: string;
|
|
46
|
+
readonly label: string;
|
|
47
|
+
readonly type: 'string' | 'number' | 'boolean' | 'uuid' | 'timestamp' | 'json';
|
|
48
|
+
readonly validOperators: readonly PolicyOperator[];
|
|
49
|
+
readonly arrayOperators: readonly PolicyOperator[];
|
|
50
|
+
readonly nullaryOperators: readonly PolicyOperator[];
|
|
51
|
+
}
|
|
52
|
+
/** The guided-builder schema for a type. */
|
|
53
|
+
export interface PolicyTypeSchema {
|
|
54
|
+
readonly typeKey: string;
|
|
55
|
+
readonly label: string;
|
|
56
|
+
readonly actions: readonly string[];
|
|
57
|
+
readonly fields: readonly PolicyFieldSchema[];
|
|
58
|
+
}
|
|
59
|
+
export type SchemaResult = {
|
|
60
|
+
ok: true;
|
|
61
|
+
schema: PolicyTypeSchema;
|
|
62
|
+
} | {
|
|
63
|
+
ok: false;
|
|
64
|
+
status: number;
|
|
65
|
+
error: string;
|
|
66
|
+
};
|
|
67
|
+
export type ListPoliciesResult = {
|
|
68
|
+
ok: true;
|
|
69
|
+
policies: PolicyRow[];
|
|
70
|
+
} | {
|
|
71
|
+
ok: false;
|
|
72
|
+
status: number;
|
|
73
|
+
error: string;
|
|
74
|
+
};
|
|
75
|
+
export type AuthorResult = {
|
|
76
|
+
ok: true;
|
|
77
|
+
policy: PolicyRow;
|
|
78
|
+
} | {
|
|
79
|
+
ok: false;
|
|
80
|
+
status: number;
|
|
81
|
+
error: string;
|
|
82
|
+
};
|
|
83
|
+
export type MutateResult = {
|
|
84
|
+
ok: true;
|
|
85
|
+
} | {
|
|
86
|
+
ok: false;
|
|
87
|
+
status: number;
|
|
88
|
+
error: string;
|
|
89
|
+
};
|
|
90
|
+
export interface RecordPolicyService {
|
|
91
|
+
schema(accessToken: string, typeKey: string, opts?: {
|
|
92
|
+
signal?: AbortSignalLike;
|
|
93
|
+
}): Promise<SchemaResult>;
|
|
94
|
+
list(accessToken: string, typeKey: string, opts?: {
|
|
95
|
+
signal?: AbortSignalLike;
|
|
96
|
+
}): Promise<ListPoliciesResult>;
|
|
97
|
+
author(accessToken: string, policy: GuidedPolicy): Promise<AuthorResult>;
|
|
98
|
+
remove(accessToken: string, policyId: string): Promise<MutateResult>;
|
|
99
|
+
}
|
|
100
|
+
export declare function createRecordPolicyService(http: HttpClient): RecordPolicyService;
|
|
101
|
+
//# sourceMappingURL=recordPolicyService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recordPolicyService.d.ts","sourceRoot":"","sources":["../../src/auth/recordPolicyService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export function createRecordPolicyService(http) {
|
|
2
|
+
function fail(r, generic) {
|
|
3
|
+
if (r.status === 401) {
|
|
4
|
+
return { ok: false, status: 401, error: 'Not authenticated (no/invalid token).' };
|
|
5
|
+
}
|
|
6
|
+
if (r.status === 403) {
|
|
7
|
+
return { ok: false, status: 403, error: 'You do not have access to do this.' };
|
|
8
|
+
}
|
|
9
|
+
if (r.status === 404) {
|
|
10
|
+
return { ok: false, status: 404, error: 'Not found.' };
|
|
11
|
+
}
|
|
12
|
+
if (r.status === 400) {
|
|
13
|
+
const message = r.data?.message;
|
|
14
|
+
return { ok: false, status: 400, error: message || generic };
|
|
15
|
+
}
|
|
16
|
+
return { ok: false, status: r.status, error: generic };
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
/**
|
|
20
|
+
* The guided-builder schema for a type — its fields + the operators to offer per field.
|
|
21
|
+
* Resolves: { ok:true, schema } | { ok:false, status, error }
|
|
22
|
+
*/
|
|
23
|
+
async schema(accessToken, typeKey, opts) {
|
|
24
|
+
const r = await http.get(`/identity/record-policies/schema?typeKey=${encodeURIComponent(typeKey)}`, { bearerToken: accessToken, ...(opts?.signal ? { signal: opts.signal } : {}) });
|
|
25
|
+
if (r.ok) {
|
|
26
|
+
return { ok: true, schema: (r.data ?? {}) };
|
|
27
|
+
}
|
|
28
|
+
return fail(r, 'Could not load the policy schema.');
|
|
29
|
+
},
|
|
30
|
+
/**
|
|
31
|
+
* This tenant's policies governing a type.
|
|
32
|
+
* Resolves: { ok:true, policies } | { ok:false, status, error }
|
|
33
|
+
*/
|
|
34
|
+
async list(accessToken, typeKey, opts) {
|
|
35
|
+
const r = await http.get(`/identity/record-policies?typeKey=${encodeURIComponent(typeKey)}`, { bearerToken: accessToken, ...(opts?.signal ? { signal: opts.signal } : {}) });
|
|
36
|
+
if (r.ok) {
|
|
37
|
+
const policies = r.data?.policies ?? [];
|
|
38
|
+
return { ok: true, policies };
|
|
39
|
+
}
|
|
40
|
+
return fail(r, 'Could not load the policies.');
|
|
41
|
+
},
|
|
42
|
+
/**
|
|
43
|
+
* Author a guided policy in the caller's own tenant (the server ignores any body tenant).
|
|
44
|
+
* Resolves: { ok:true, policy } | { ok:false, status, error }
|
|
45
|
+
*/
|
|
46
|
+
async author(accessToken, policy) {
|
|
47
|
+
const r = await http.post('/identity/record-policies', policy ?? {}, {
|
|
48
|
+
bearerToken: accessToken,
|
|
49
|
+
});
|
|
50
|
+
if (r.ok) {
|
|
51
|
+
const authored = r.data?.policy;
|
|
52
|
+
if (authored)
|
|
53
|
+
return { ok: true, policy: authored };
|
|
54
|
+
return fail({ status: r.status, data: r.data }, 'Policy authored but not returned.');
|
|
55
|
+
}
|
|
56
|
+
return fail(r, 'Could not author the policy.');
|
|
57
|
+
},
|
|
58
|
+
/**
|
|
59
|
+
* Delete a policy the caller owns (tenant-scoped server-side; a foreign id → 404).
|
|
60
|
+
* Resolves: { ok:true } | { ok:false, status, error }
|
|
61
|
+
*/
|
|
62
|
+
async remove(accessToken, policyId) {
|
|
63
|
+
const r = await http.delete(`/identity/record-policies/${encodeURIComponent(policyId)}`, {}, { bearerToken: accessToken });
|
|
64
|
+
if (r.ok)
|
|
65
|
+
return { ok: true };
|
|
66
|
+
return fail(r, 'Could not delete the policy.');
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=recordPolicyService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recordPolicyService.js","sourceRoot":"","sources":["../../src/auth/recordPolicyService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createRecordShareService — platform-agnostic calls to the identity feature's OWNER-SHARE
|
|
3
|
+
* surface (§9.2 / list-scoping engine Phase 6). Like the other services, it takes an injected
|
|
4
|
+
* HTTP client, carries no platform code, and passes the bearer token per call. Every method
|
|
5
|
+
* resolves to a plain result object (never throws): `{ ok:true, ... }` on success,
|
|
6
|
+
* `{ ok:false, status, error }` on any non-2xx (401 = not authenticated, 403 = not the owner /
|
|
7
|
+
* denied, 400 = the server's message, else generic).
|
|
8
|
+
*
|
|
9
|
+
* The server routes these hit (all `@Classified` on the `record_share` meta-type):
|
|
10
|
+
* GET /identity/record-shares?typeKey=&recordId= (a record's shares — owner only)
|
|
11
|
+
* POST /identity/record-shares (share — owner only)
|
|
12
|
+
* DELETE /identity/record-shares (revoke — owner only)
|
|
13
|
+
*
|
|
14
|
+
* ⛔ The sharer + tenant are NEVER sent by the client — the server proves ownership from the
|
|
15
|
+
* authenticated principal (a body owner/tenant is ignored). ⛔ The list returns grantee NAMES
|
|
16
|
+
* (`granteeName`); the `granteeUuid` rides only as the revoke API key, never a display value.
|
|
17
|
+
*/
|
|
18
|
+
import type { HttpClient, AbortSignalLike } from '../http/types.js';
|
|
19
|
+
/** Who a share is granted to. */
|
|
20
|
+
export type ShareGranteeKind = 'user' | 'role';
|
|
21
|
+
/** The share/unshare request — grantee + action ONLY (never a tenant/sharer/owner field). */
|
|
22
|
+
export interface ShareRequest {
|
|
23
|
+
readonly typeKey: string;
|
|
24
|
+
readonly recordId: string;
|
|
25
|
+
readonly granteeKind: ShareGranteeKind;
|
|
26
|
+
readonly granteeUuid: string;
|
|
27
|
+
readonly action: string;
|
|
28
|
+
}
|
|
29
|
+
/** A share as the UI sees it — a resolved NAME (never a raw uuid) + the revoke API key. */
|
|
30
|
+
export interface ShareView {
|
|
31
|
+
readonly granteeName: string;
|
|
32
|
+
readonly granteeKind: ShareGranteeKind;
|
|
33
|
+
/** API key for revoke only — the UI renders `granteeName`. */
|
|
34
|
+
readonly granteeUuid: string;
|
|
35
|
+
readonly action: string;
|
|
36
|
+
}
|
|
37
|
+
export type ListSharesResult = {
|
|
38
|
+
ok: true;
|
|
39
|
+
shares: ShareView[];
|
|
40
|
+
} | {
|
|
41
|
+
ok: false;
|
|
42
|
+
status: number;
|
|
43
|
+
error: string;
|
|
44
|
+
};
|
|
45
|
+
export type MutateResult = {
|
|
46
|
+
ok: true;
|
|
47
|
+
} | {
|
|
48
|
+
ok: false;
|
|
49
|
+
status: number;
|
|
50
|
+
error: string;
|
|
51
|
+
};
|
|
52
|
+
export interface RecordShareService {
|
|
53
|
+
listShares(accessToken: string, typeKey: string, recordId: string, opts?: {
|
|
54
|
+
signal?: AbortSignalLike;
|
|
55
|
+
}): Promise<ListSharesResult>;
|
|
56
|
+
share(accessToken: string, req: ShareRequest): Promise<MutateResult>;
|
|
57
|
+
unshare(accessToken: string, req: ShareRequest): Promise<MutateResult>;
|
|
58
|
+
}
|
|
59
|
+
export declare function createRecordShareService(http: HttpClient): RecordShareService;
|
|
60
|
+
//# sourceMappingURL=recordShareService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recordShareService.d.ts","sourceRoot":"","sources":["../../src/auth/recordShareService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEpE,iCAAiC;AACjC,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,CAAC;AAE/C,6FAA6F;AAC7F,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,2FAA2F;AAC3F,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC,8DAA8D;IAC9D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,SAAS,EAAE,CAAA;CAAE,GACjC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AACjD,MAAM,MAAM,YAAY,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvF,MAAM,WAAW,kBAAkB;IACjC,UAAU,CACR,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,eAAe,CAAA;KAAE,GAClC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC7B,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACrE,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACxE;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,UAAU,GAAG,kBAAkB,CA2D7E"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export function createRecordShareService(http) {
|
|
2
|
+
function fail(r, generic) {
|
|
3
|
+
if (r.status === 401) {
|
|
4
|
+
return { ok: false, status: 401, error: 'Not authenticated (no/invalid token).' };
|
|
5
|
+
}
|
|
6
|
+
if (r.status === 403) {
|
|
7
|
+
return { ok: false, status: 403, error: 'Only the record owner may do this.' };
|
|
8
|
+
}
|
|
9
|
+
if (r.status === 400) {
|
|
10
|
+
const message = r.data?.message;
|
|
11
|
+
return { ok: false, status: 400, error: message || generic };
|
|
12
|
+
}
|
|
13
|
+
return { ok: false, status: r.status, error: generic };
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
/**
|
|
17
|
+
* The shares currently on a record the caller owns — grantee NAMES resolved.
|
|
18
|
+
* Resolves: { ok:true, shares } | { ok:false, status, error }
|
|
19
|
+
*/
|
|
20
|
+
async listShares(accessToken, typeKey, recordId, opts) {
|
|
21
|
+
const r = await http.get(`/identity/record-shares?typeKey=${encodeURIComponent(typeKey)}&recordId=${encodeURIComponent(recordId)}`, { bearerToken: accessToken, ...(opts?.signal ? { signal: opts.signal } : {}) });
|
|
22
|
+
if (r.ok) {
|
|
23
|
+
const shares = r.data?.shares ?? [];
|
|
24
|
+
return { ok: true, shares };
|
|
25
|
+
}
|
|
26
|
+
return fail(r, 'Could not load the shares.');
|
|
27
|
+
},
|
|
28
|
+
/**
|
|
29
|
+
* Share a record the caller owns with a user/role for an action.
|
|
30
|
+
* Resolves: { ok:true } | { ok:false, status, error }
|
|
31
|
+
*/
|
|
32
|
+
async share(accessToken, req) {
|
|
33
|
+
const r = await http.post('/identity/record-shares', req ?? {}, {
|
|
34
|
+
bearerToken: accessToken,
|
|
35
|
+
});
|
|
36
|
+
if (r.ok)
|
|
37
|
+
return { ok: true };
|
|
38
|
+
return fail(r, 'Could not share the record.');
|
|
39
|
+
},
|
|
40
|
+
/**
|
|
41
|
+
* Revoke a share (the same tuple). The DELETE carries the tuple in the body.
|
|
42
|
+
* Resolves: { ok:true } | { ok:false, status, error }
|
|
43
|
+
*/
|
|
44
|
+
async unshare(accessToken, req) {
|
|
45
|
+
const r = await http.delete('/identity/record-shares', req ?? {}, {
|
|
46
|
+
bearerToken: accessToken,
|
|
47
|
+
});
|
|
48
|
+
if (r.ok)
|
|
49
|
+
return { ok: true };
|
|
50
|
+
return fail(r, 'Could not revoke the share.');
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=recordShareService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recordShareService.js","sourceRoot":"","sources":["../../src/auth/recordShareService.ts"],"names":[],"mappings":"AAwDA,MAAM,UAAU,wBAAwB,CAAC,IAAgB;IACvD,SAAS,IAAI,CACX,CAAqC,EACrC,OAAe;QAEf,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACrB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,uCAAuC,EAAE,CAAC;QACpF,CAAC;QACD,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACrB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,oCAAoC,EAAE,CAAC;QACjF,CAAC;QACD,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACrB,MAAM,OAAO,GAAI,CAAC,CAAC,IAAgD,EAAE,OAAO,CAAC;YAC7E,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,IAAI,OAAO,EAAE,CAAC;QAC/D,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IACzD,CAAC;IAED,OAAO;QACL;;;WAGG;QACH,KAAK,CAAC,UAAU,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI;YACnD,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,GAAG,CACtB,mCAAmC,kBAAkB,CAAC,OAAO,CAAC,aAAa,kBAAkB,CAAC,QAAQ,CAAC,EAAE,EACzG,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAC/E,CAAC;YACF,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC;gBACT,MAAM,MAAM,GAAI,CAAC,CAAC,IAAoD,EAAE,MAAM,IAAI,EAAE,CAAC;gBACrF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YAC9B,CAAC;YACD,OAAO,IAAI,CAAC,CAAC,EAAE,4BAA4B,CAAC,CAAC;QAC/C,CAAC;QAED;;;WAGG;QACH,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG;YAC1B,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,yBAAyB,EAAE,GAAG,IAAI,EAAE,EAAE;gBAC9D,WAAW,EAAE,WAAW;aACzB,CAAC,CAAC;YACH,IAAI,CAAC,CAAC,EAAE;gBAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC,CAAC,EAAE,6BAA6B,CAAC,CAAC;QAChD,CAAC;QAED;;;WAGG;QACH,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG;YAC5B,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,yBAAyB,EAAE,GAAG,IAAI,EAAE,EAAE;gBAChE,WAAW,EAAE,WAAW;aACzB,CAAC,CAAC;YACH,IAAI,CAAC,CAAC,EAAE;gBAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC,CAAC,EAAE,6BAA6B,CAAC,CAAC;QAChD,CAAC;KACF,CAAC;AACJ,CAAC"}
|