@amalgm/core 0.4.1 → 0.4.2

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.
@@ -2,5 +2,6 @@ export * from './policy.js';
2
2
  export * from './claims.js';
3
3
  export * from './dpop.js';
4
4
  export * from './broker.js';
5
+ export * from './resource.js';
5
6
  export * from './key-transition.js';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/identity/authorization/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/identity/authorization/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC"}
@@ -2,5 +2,6 @@ export * from './policy.js';
2
2
  export * from './claims.js';
3
3
  export * from './dpop.js';
4
4
  export * from './broker.js';
5
+ export * from './resource.js';
5
6
  export * from './key-transition.js';
6
7
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/identity/authorization/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/identity/authorization/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC"}
@@ -2,6 +2,8 @@
2
2
  export declare const AUTHORIZATION_POLICY: Readonly<{
3
3
  readonly 'amalgm-api-proxy': readonly string[];
4
4
  readonly 'amalgm-apps': readonly string[];
5
+ readonly 'amalgm-automations': readonly string[];
6
+ readonly 'amalgm-channels': readonly string[];
5
7
  }>;
6
8
  export type AuthorizationAudience = keyof typeof AUTHORIZATION_POLICY;
7
9
  export type AuthorizationScope = (typeof AUTHORIZATION_POLICY)[AuthorizationAudience][number];
@@ -1 +1 @@
1
- {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../../src/identity/authorization/policy.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB;;;EAatB,CAAC;AAEZ,MAAM,MAAM,qBAAqB,GAAG,MAAM,OAAO,oBAAoB,CAAC;AACtE,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9F,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAEtF;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,SAAS,kBAAkB,EAAE,CAEhG;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,qBAAqB,EAC/B,MAAM,EAAE,SAAS,MAAM,EAAE,GACxB,SAAS,kBAAkB,EAAE,CAQ/B;AAED,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,IAAI,EAAE,iBAAiB,GAAG,mBAAmB,CAAC;gBAE3C,IAAI,EAAE,iBAAiB,GAAG,mBAAmB;CAO1D"}
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../../src/identity/authorization/policy.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB;;;;;EAuBtB,CAAC;AAEZ,MAAM,MAAM,qBAAqB,GAAG,MAAM,OAAO,oBAAoB,CAAC;AACtE,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9F,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,qBAAqB,CAEtF;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,SAAS,kBAAkB,EAAE,CAEhG;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,qBAAqB,EAC/B,MAAM,EAAE,SAAS,MAAM,EAAE,GACxB,SAAS,kBAAkB,EAAE,CAQ/B;AAED,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,IAAI,EAAE,iBAAiB,GAAG,mBAAmB,CAAC;gBAE3C,IAAI,EAAE,iBAAiB,GAAG,mBAAmB;CAO1D"}
@@ -12,6 +12,16 @@ export const AUTHORIZATION_POLICY = Object.freeze({
12
12
  'apps:read',
13
13
  'apps:run',
14
14
  ]),
15
+ 'amalgm-automations': Object.freeze([
16
+ 'automations:read',
17
+ 'automations:write',
18
+ 'runs:execute',
19
+ 'runs:read',
20
+ ]),
21
+ 'amalgm-channels': Object.freeze([
22
+ 'channels:read',
23
+ 'channels:send',
24
+ ]),
15
25
  });
16
26
  export function isAuthorizationAudience(value) {
17
27
  return typeof value === 'string' && value in AUTHORIZATION_POLICY;
@@ -1 +1 @@
1
- {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../../src/identity/authorization/policy.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC;IAChD,kBAAkB,EAAE,MAAM,CAAC,MAAM,CAAC;QAChC,eAAe;QACf,aAAa;QACb,YAAY;QACZ,YAAY;QACZ,SAAS;KACV,CAAC;IACF,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC;QAC3B,aAAa;QACb,WAAW;QACX,UAAU;KACX,CAAC;CACM,CAAC,CAAC;AAKZ,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,oBAAoB,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAA+B;IAC/D,OAAO,oBAAoB,CAAC,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,QAA+B,EAC/B,MAAyB;IAEzB,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACpC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,wBAAwB,CAAC,iBAAiB,CAAC,CAAC;IAC/E,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,wBAAwB,CAAC,mBAAmB,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAkC,CAAC;AACvE,CAAC;AAED,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACxC,IAAI,CAA0C;IAEvD,YAAY,IAA6C;QACvD,KAAK,CAAC,IAAI,KAAK,iBAAiB;YAC9B,CAAC,CAAC,8CAA8C;YAChD,CAAC,CAAC,sDAAsD,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../../src/identity/authorization/policy.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC;IAChD,kBAAkB,EAAE,MAAM,CAAC,MAAM,CAAC;QAChC,eAAe;QACf,aAAa;QACb,YAAY;QACZ,YAAY;QACZ,SAAS;KACV,CAAC;IACF,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC;QAC3B,aAAa;QACb,WAAW;QACX,UAAU;KACX,CAAC;IACF,oBAAoB,EAAE,MAAM,CAAC,MAAM,CAAC;QAClC,kBAAkB;QAClB,mBAAmB;QACnB,cAAc;QACd,WAAW;KACZ,CAAC;IACF,iBAAiB,EAAE,MAAM,CAAC,MAAM,CAAC;QAC/B,eAAe;QACf,eAAe;KAChB,CAAC;CACM,CAAC,CAAC;AAKZ,MAAM,UAAU,uBAAuB,CAAC,KAAc;IACpD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,oBAAoB,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAA+B;IAC/D,OAAO,oBAAoB,CAAC,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,QAA+B,EAC/B,MAAyB;IAEzB,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACpC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,wBAAwB,CAAC,iBAAiB,CAAC,CAAC;IAC/E,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,wBAAwB,CAAC,mBAAmB,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAkC,CAAC;AACvE,CAAC;AAED,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACxC,IAAI,CAA0C;IAEvD,YAAY,IAA6C;QACvD,KAAK,CAAC,IAAI,KAAK,iBAAiB;YAC9B,CAAC,CAAC,8CAA8C;YAChD,CAAC,CAAC,sDAAsD,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
@@ -0,0 +1,39 @@
1
+ import { type AuthorizationAudience, type AuthorizationScope } from './policy.js';
2
+ export interface VerifiedJwt {
3
+ readonly header: Readonly<Record<string, unknown>>;
4
+ readonly claims: Readonly<Record<string, unknown>>;
5
+ }
6
+ export interface MachineResourceVerifierPorts {
7
+ verifyAccessToken(token: string): Promise<VerifiedJwt>;
8
+ verifyDpopProof(proof: string): Promise<VerifiedJwt>;
9
+ jwkThumbprint(jwk: Readonly<Record<string, unknown>>): Promise<string>;
10
+ accessTokenHash(token: string): Promise<string>;
11
+ consumeProof(keyThumbprint: string, jti: string): Promise<boolean>;
12
+ nowSeconds(): number;
13
+ }
14
+ export interface MachineResourceRequest {
15
+ readonly authorization: string | null | undefined;
16
+ readonly dpop: string | null | undefined;
17
+ readonly method: string;
18
+ readonly url: string;
19
+ readonly issuer: string;
20
+ readonly audience: AuthorizationAudience;
21
+ readonly requiredScopes: readonly AuthorizationScope[];
22
+ }
23
+ export interface AuthorizedMachinePrincipal {
24
+ readonly userId: string;
25
+ readonly computerId: string;
26
+ readonly clientId: 'amalgm-shell';
27
+ readonly scopes: readonly AuthorizationScope[];
28
+ readonly keyThumbprint: string;
29
+ }
30
+ /**
31
+ * The one resource-server decision for every hosted Amalgm product. Crypto
32
+ * and shared replay persistence are injected; claims and DPoP law stay here.
33
+ */
34
+ export declare function authorizeMachineResource(request: MachineResourceRequest, ports: MachineResourceVerifierPorts): Promise<AuthorizedMachinePrincipal>;
35
+ export declare class MachineResourceAuthorizationError extends Error {
36
+ readonly code: string;
37
+ constructor(code: string);
38
+ }
39
+ //# sourceMappingURL=resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../../src/identity/authorization/resource.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACxB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,4BAA4B;IAC3C,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACvD,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACrD,aAAa,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvE,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnE,UAAU,IAAI,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAC;IACzC,QAAQ,CAAC,cAAc,EAAE,SAAS,kBAAkB,EAAE,CAAC;CACxD;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAC/C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,sBAAsB,EAC/B,KAAK,EAAE,4BAA4B,GAClC,OAAO,CAAC,0BAA0B,CAAC,CAwErC;AA8DD,qBAAa,iCAAkC,SAAQ,KAAK;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM;CAKzB"}
@@ -0,0 +1,132 @@
1
+ import { ACCESS_TOKEN_CLOCK_SKEW_SECONDS, ACCESS_TOKEN_TTL_SECONDS, DPOP_PROOF_MAX_AGE_SECONDS, scopesFromClaim, } from './claims.js';
2
+ import { normalizeDpopHtu, normalizeDpopMethod } from './dpop.js';
3
+ import { canonicalScopes, } from './policy.js';
4
+ /**
5
+ * The one resource-server decision for every hosted Amalgm product. Crypto
6
+ * and shared replay persistence are injected; claims and DPoP law stay here.
7
+ */
8
+ export async function authorizeMachineResource(request, ports) {
9
+ const token = dpopAccessToken(request.authorization);
10
+ const proofValue = requiredText(request.dpop, 'dpop_required');
11
+ const now = ports.nowSeconds();
12
+ if (!Number.isInteger(now))
13
+ throw new MachineResourceAuthorizationError('invalid_clock');
14
+ const access = await verified(() => ports.verifyAccessToken(token), 'invalid_access_token');
15
+ assertHeader(access.header, 'at+jwt', false);
16
+ const claims = access.claims;
17
+ if (claims.iss !== request.issuer || claims.aud !== request.audience) {
18
+ throw new MachineResourceAuthorizationError('access_target_mismatch');
19
+ }
20
+ const issuedAt = integerClaim(claims.iat, 'invalid_access_claims');
21
+ const expiresAt = integerClaim(claims.exp, 'invalid_access_claims');
22
+ if (issuedAt > now + ACCESS_TOKEN_CLOCK_SKEW_SECONDS
23
+ || expiresAt <= now - ACCESS_TOKEN_CLOCK_SKEW_SECONDS
24
+ || expiresAt - issuedAt > ACCESS_TOKEN_TTL_SECONDS)
25
+ throw new MachineResourceAuthorizationError('invalid_access_lifetime');
26
+ const userId = claimText(claims.sub, 'invalid_access_claims');
27
+ const computerId = claimText(claims.computer_id, 'invalid_access_claims');
28
+ if (claims.client_id !== 'amalgm-shell') {
29
+ throw new MachineResourceAuthorizationError('invalid_client');
30
+ }
31
+ claimText(claims.jti, 'invalid_access_claims');
32
+ const confirmation = record(claims.cnf, 'invalid_access_claims');
33
+ const keyThumbprint = claimText(confirmation.jkt, 'invalid_access_claims');
34
+ if (!/^[A-Za-z0-9_-]{43}$/.test(keyThumbprint)) {
35
+ throw new MachineResourceAuthorizationError('invalid_access_claims');
36
+ }
37
+ const rawScopes = scopesFromClaim(claims.scope);
38
+ let scopes;
39
+ try {
40
+ scopes = canonicalScopes(request.audience, rawScopes);
41
+ }
42
+ catch {
43
+ throw new MachineResourceAuthorizationError('invalid_scope');
44
+ }
45
+ const requiredScopes = canonicalScopes(request.audience, request.requiredScopes);
46
+ if (requiredScopes.some((scope) => !scopes.includes(scope))) {
47
+ throw new MachineResourceAuthorizationError('insufficient_scope');
48
+ }
49
+ const proof = await verified(() => ports.verifyDpopProof(proofValue), 'invalid_dpop_proof');
50
+ const publicJwk = assertHeader(proof.header, 'dpop+jwt', true);
51
+ const proofClaims = proof.claims;
52
+ if (proofClaims.htm !== normalizeDpopMethod(request.method)
53
+ || proofClaims.htu !== normalizeDpopHtu(request.url)
54
+ || proofClaims.ath !== await ports.accessTokenHash(token))
55
+ throw new MachineResourceAuthorizationError('dpop_target_mismatch');
56
+ const proofIat = integerClaim(proofClaims.iat, 'invalid_dpop_claims');
57
+ const proofJti = claimText(proofClaims.jti, 'invalid_dpop_claims');
58
+ if (Math.abs(now - proofIat) > DPOP_PROOF_MAX_AGE_SECONDS
59
+ || proofJti.length > 200)
60
+ throw new MachineResourceAuthorizationError('invalid_dpop_claims');
61
+ if (await ports.jwkThumbprint(publicJwk) !== keyThumbprint) {
62
+ throw new MachineResourceAuthorizationError('dpop_key_mismatch');
63
+ }
64
+ if (!await ports.consumeProof(keyThumbprint, proofJti)) {
65
+ throw new MachineResourceAuthorizationError('dpop_replayed');
66
+ }
67
+ return Object.freeze({
68
+ userId,
69
+ computerId,
70
+ clientId: 'amalgm-shell',
71
+ scopes,
72
+ keyThumbprint,
73
+ });
74
+ }
75
+ function dpopAccessToken(value) {
76
+ const match = value?.match(/^DPoP\s+(\S+)$/);
77
+ if (!match?.[1])
78
+ throw new MachineResourceAuthorizationError('dpop_access_required');
79
+ return match[1];
80
+ }
81
+ function assertHeader(header, type, requiresJwk) {
82
+ if (header.typ !== type || header.alg !== 'ES256') {
83
+ throw new MachineResourceAuthorizationError('invalid_jwt_header');
84
+ }
85
+ if (!requiresJwk)
86
+ return Object.freeze({});
87
+ const jwk = record(header.jwk, 'invalid_jwt_header');
88
+ if (jwk.kty !== 'EC'
89
+ || jwk.crv !== 'P-256'
90
+ || typeof jwk.x !== 'string'
91
+ || typeof jwk.y !== 'string'
92
+ || 'd' in jwk)
93
+ throw new MachineResourceAuthorizationError('invalid_jwt_header');
94
+ return jwk;
95
+ }
96
+ async function verified(operation, code) {
97
+ try {
98
+ return await operation();
99
+ }
100
+ catch {
101
+ throw new MachineResourceAuthorizationError(code);
102
+ }
103
+ }
104
+ function requiredText(value, code) {
105
+ if (typeof value !== 'string' || !value.trim()) {
106
+ throw new MachineResourceAuthorizationError(code);
107
+ }
108
+ return value.trim();
109
+ }
110
+ function claimText(value, code) {
111
+ return requiredText(value, code);
112
+ }
113
+ function integerClaim(value, code) {
114
+ if (!Number.isInteger(value))
115
+ throw new MachineResourceAuthorizationError(code);
116
+ return value;
117
+ }
118
+ function record(value, code) {
119
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
120
+ throw new MachineResourceAuthorizationError(code);
121
+ }
122
+ return value;
123
+ }
124
+ export class MachineResourceAuthorizationError extends Error {
125
+ code;
126
+ constructor(code) {
127
+ super(code);
128
+ this.name = 'MachineResourceAuthorizationError';
129
+ this.code = code;
130
+ }
131
+ }
132
+ //# sourceMappingURL=resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource.js","sourceRoot":"","sources":["../../../src/identity/authorization/resource.ts"],"names":[],"mappings":"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"}
@@ -36,6 +36,15 @@ Import `@amalgm/core/authorization` for:
36
36
  - URL and method normalization;
37
37
  - the closed initial-pin, ordinary-reuse, and explicit-recovery transition;
38
38
  - `CredentialBroker`, whose issuer and signer effects are injected by Shell.
39
+ - `authorizeMachineResource`, whose crypto and replay effects are injected by
40
+ a hosted product while Core makes the one claims-and-DPoP decision.
41
+
42
+ The closed service grants are:
43
+
44
+ - `amalgm-api-proxy`: one scope per supported LLM provider;
45
+ - `amalgm-apps`: read, run, and manage apps;
46
+ - `amalgm-automations`: read/write definitions and read/execute runs;
47
+ - `amalgm-channels`: read delivery history and send to the current user.
39
48
 
40
49
  The default access lifetime is 15 minutes. Cached credentials refresh at least
41
50
  two minutes early, with up to 30 seconds of jitter. DPoP proofs are one-request
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amalgm/core",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "The Amalgm kernel SDK — identity, transport, supervision, and host capability contracts behind host-injected adapters.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",