@apoa/core 0.2.1 → 0.2.3

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/index.d.ts CHANGED
@@ -235,6 +235,35 @@ interface APOAClientOptions {
235
235
  keyResolver?: KeyResolver;
236
236
  defaultSigningOptions?: Partial<SigningOptions>;
237
237
  }
238
+ /** Options for the application-facing APOA facade. */
239
+ interface APOAOptions extends Omit<APOAClientOptions, 'defaultSigningOptions'> {
240
+ privateKey?: CryptoKey;
241
+ algorithm?: 'EdDSA' | 'ES256';
242
+ kid?: string;
243
+ }
244
+ /** Duration string for convenience expiry fields, e.g. `15m`, `2h`, `30d`. */
245
+ type DurationString = `${number}${'s' | 'm' | 'h' | 'd'}`;
246
+ /** One-service grant input accepted by the application-facing facade. */
247
+ interface SimpleGrantInput {
248
+ principal: string | Principal;
249
+ agent: string | Agent;
250
+ service?: string;
251
+ scopes?: string[];
252
+ services?: ServiceAuthorization[];
253
+ constraints?: ConstraintMap;
254
+ rules?: Rule[];
255
+ expires?: Date | string;
256
+ expiresIn?: DurationString;
257
+ revocable?: boolean;
258
+ delegatable?: boolean;
259
+ maxDelegationDepth?: number;
260
+ metadata?: TokenMetadata;
261
+ accessMode?: AccessMode;
262
+ browserConfig?: BrowserSessionConfig;
263
+ apiConfig?: APIAccessConfig;
264
+ agentProvider?: AgentProvider;
265
+ legal?: LegalFramework;
266
+ }
238
267
  /** The configured APOA client. */
239
268
  interface APOAClient {
240
269
  createToken(definition: APOADefinition, options?: SigningOptions): Promise<APOAToken>;
@@ -596,4 +625,25 @@ declare function createJWKSResolver(url: string, options?: JWKSResolverOptions):
596
625
  */
597
626
  declare function createClient(options?: APOAClientOptions): APOAClient;
598
627
 
599
- export { type APIAccessConfig, type APOAClient, type APOAClientOptions, type APOADefinition, APOAError, type APOAToken, type AccessMode, type Agent, type AgentProvider, AttenuationViolationError, type AuditDetailValue, type AuditEntry, type AuditQueryOptions, type AuditStore, type AuthorizationResult, type AuthorizeOptions, type BrowserSessionConfig, ChainVerificationError, type ChainVerificationResult, type ConstraintMap, type ConstraintValue, DefinitionValidationError, type DelegationChain, type DelegationDefinition, type JWK, type JWKS, type JWKSResolverOptions, type KeyResolver, type LegalFramework, MemoryAuditStore, MemoryRevocationStore, MetadataValidationError, type MetadataValue, type OnRuleViolation, type Principal, type PublicKeyToJWKOptions, RevocationError, type RevocationOptions, type RevocationRecord, type RevocationStore, type Rule, RuleEnforcementError, type RuleViolation, type ScopeCheckResult, ScopeViolationError, type ServiceAuthorization, type SigningOptions, TokenExpiredError, type TokenMetadata, type ValidationOptions, type ValidationResult, authorize, buildJWKS, cascadeRevoke, checkConstraint, checkScope, createClient, createJWKSResolver, createToken, decodeHeader, delegate, generateKeyPair, getAuditTrail, getAuditTrailByService, getDelegationAncestorIds, isBeforeNotBefore, isExpired, isRevoked, logAction, matchScope, parseDefinition, parseScope, publicKeyToJWK, revoke, sign, signToken, validateToken, verify, verifyAttenuation, verifyChain, verifySignature };
628
+ /**
629
+ * Application-facing APOA facade.
630
+ *
631
+ * This keeps the protocol-level APIs intact while giving app developers a
632
+ * smaller first path: configure once, then use namespaced resources.
633
+ */
634
+ declare class APOA {
635
+ private readonly client;
636
+ readonly tokens: {
637
+ create: (definition: APOADefinition, options?: SigningOptions) => Promise<APOAToken>;
638
+ createGrant: (input: SimpleGrantInput, options?: SigningOptions) => Promise<APOAToken>;
639
+ validate: (token: string | APOAToken, options?: Omit<ValidationOptions, 'revocationStore'>) => Promise<ValidationResult>;
640
+ parse: (input: string, format?: 'yaml' | 'json') => APOADefinition;
641
+ };
642
+ readonly authorizations: {
643
+ check: (token: APOAToken, service: string, action: string, options?: Omit<AuthorizeOptions, 'revocationStore' | 'auditStore'>) => Promise<AuthorizationResult>;
644
+ };
645
+ constructor(options?: APOAOptions);
646
+ generateKeyPair(algorithm?: 'EdDSA' | 'ES256'): Promise<CryptoKeyPair>;
647
+ }
648
+
649
+ export { type APIAccessConfig, APOA, type APOAClient, type APOAClientOptions, type APOADefinition, APOAError, type APOAOptions, type APOAToken, type AccessMode, type Agent, type AgentProvider, AttenuationViolationError, type AuditDetailValue, type AuditEntry, type AuditQueryOptions, type AuditStore, type AuthorizationResult, type AuthorizeOptions, type BrowserSessionConfig, ChainVerificationError, type ChainVerificationResult, type ConstraintMap, type ConstraintValue, DefinitionValidationError, type DelegationChain, type DelegationDefinition, type DurationString, type JWK, type JWKS, type JWKSResolverOptions, type KeyResolver, type LegalFramework, MemoryAuditStore, MemoryRevocationStore, MetadataValidationError, type MetadataValue, type OnRuleViolation, type Principal, type PublicKeyToJWKOptions, RevocationError, type RevocationOptions, type RevocationRecord, type RevocationStore, type Rule, RuleEnforcementError, type RuleViolation, type ScopeCheckResult, ScopeViolationError, type ServiceAuthorization, type SigningOptions, type SimpleGrantInput, TokenExpiredError, type TokenMetadata, type ValidationOptions, type ValidationResult, authorize, buildJWKS, cascadeRevoke, checkConstraint, checkScope, createClient, createJWKSResolver, createToken, decodeHeader, delegate, generateKeyPair, getAuditTrail, getAuditTrailByService, getDelegationAncestorIds, isBeforeNotBefore, isExpired, isRevoked, logAction, matchScope, parseDefinition, parseScope, publicKeyToJWK, revoke, sign, signToken, validateToken, verify, verifyAttenuation, verifyChain, verifySignature };
package/dist/index.js CHANGED
@@ -1252,7 +1252,9 @@ function createClient(options) {
1252
1252
  const defaultSigningOptions = options?.defaultSigningOptions;
1253
1253
  function mergeSigningOptions(opts) {
1254
1254
  if (!opts && !defaultSigningOptions?.privateKey) {
1255
- throw new Error("No signing options provided and no defaultSigningOptions.privateKey configured");
1255
+ throw new Error(
1256
+ "APOA needs a private key to create tokens. Pass `privateKey` to `new APOA({ privateKey })`, configure `createClient({ defaultSigningOptions: { privateKey } })`, or pass signing options to `createToken(...)`."
1257
+ );
1256
1258
  }
1257
1259
  return {
1258
1260
  ...defaultSigningOptions,
@@ -1313,7 +1315,147 @@ function createClient(options) {
1313
1315
  }
1314
1316
  };
1315
1317
  }
1318
+
1319
+ // src/apoa.ts
1320
+ var APOA = class {
1321
+ client;
1322
+ tokens;
1323
+ authorizations;
1324
+ constructor(options = {}) {
1325
+ const { privateKey, algorithm, kid, ...clientOptions } = options;
1326
+ this.client = createClient({
1327
+ ...clientOptions,
1328
+ defaultSigningOptions: privateKey ? { privateKey, algorithm, kid } : void 0
1329
+ });
1330
+ this.tokens = {
1331
+ create: (definition, signingOptions) => this.client.createToken(definition, signingOptions),
1332
+ createGrant: async (input, signingOptions) => this.client.createToken(normalizeGrantInput(input), signingOptions),
1333
+ validate: (token, validationOptions) => this.client.validateToken(token, validationOptions),
1334
+ parse: (input, format) => this.client.parseDefinition(input, format)
1335
+ };
1336
+ this.authorizations = {
1337
+ check: (token, service, action, authorizeOptions) => this.client.authorize(token, service, action, authorizeOptions)
1338
+ };
1339
+ }
1340
+ async generateKeyPair(algorithm) {
1341
+ return this.client.generateKeyPair(algorithm);
1342
+ }
1343
+ };
1344
+ function normalizeGrantInput(input) {
1345
+ const errors = [];
1346
+ if (!input || typeof input !== "object") {
1347
+ throw invalidGrantInput(["input must be an object"]);
1348
+ }
1349
+ const principal = normalizePrincipal(input.principal, errors);
1350
+ const agent = normalizeAgent(input.agent, errors);
1351
+ const services = normalizeServices(input, errors);
1352
+ const expires = normalizeExpires(input, errors);
1353
+ if (errors.length > 0 || !principal || !agent || services.length === 0 || !expires) {
1354
+ throw invalidGrantInput(errors);
1355
+ }
1356
+ return {
1357
+ principal,
1358
+ agent,
1359
+ services,
1360
+ expires,
1361
+ ...input.rules ? { rules: input.rules } : {},
1362
+ ...input.revocable !== void 0 ? { revocable: input.revocable } : {},
1363
+ ...input.delegatable !== void 0 ? { delegatable: input.delegatable } : {},
1364
+ ...input.maxDelegationDepth !== void 0 ? { maxDelegationDepth: input.maxDelegationDepth } : {},
1365
+ ...input.metadata ? { metadata: input.metadata } : {},
1366
+ ...input.agentProvider ? { agentProvider: input.agentProvider } : {},
1367
+ ...input.legal ? { legal: input.legal } : {}
1368
+ };
1369
+ }
1370
+ function normalizePrincipal(principal, errors) {
1371
+ if (typeof principal === "string" && principal.trim()) {
1372
+ return { id: principal.trim() };
1373
+ }
1374
+ if (principal && typeof principal === "object" && principal.id) {
1375
+ return principal;
1376
+ }
1377
+ errors.push("principal is required; pass a DID string or { id }");
1378
+ return void 0;
1379
+ }
1380
+ function normalizeAgent(agent, errors) {
1381
+ if (typeof agent === "string" && agent.trim()) {
1382
+ return { id: agent.trim() };
1383
+ }
1384
+ if (agent && typeof agent === "object" && agent.id) {
1385
+ return agent;
1386
+ }
1387
+ errors.push("agent is required; pass a DID string or { id }");
1388
+ return void 0;
1389
+ }
1390
+ function normalizeServices(input, errors) {
1391
+ if (input.services) {
1392
+ if (!Array.isArray(input.services) || input.services.length === 0) {
1393
+ errors.push("services must be a non-empty array when provided");
1394
+ return [];
1395
+ }
1396
+ return input.services;
1397
+ }
1398
+ if (!input.service) {
1399
+ errors.push("service is required unless services is provided");
1400
+ return [];
1401
+ }
1402
+ if (!input.scopes || !Array.isArray(input.scopes) || input.scopes.length === 0) {
1403
+ errors.push("scopes must be a non-empty array unless services is provided");
1404
+ return [];
1405
+ }
1406
+ return [{
1407
+ service: input.service,
1408
+ scopes: input.scopes,
1409
+ ...input.constraints ? { constraints: input.constraints } : {},
1410
+ ...input.accessMode ? { accessMode: input.accessMode } : {},
1411
+ ...input.browserConfig ? { browserConfig: input.browserConfig } : {},
1412
+ ...input.apiConfig ? { apiConfig: input.apiConfig } : {}
1413
+ }];
1414
+ }
1415
+ function normalizeExpires(input, errors) {
1416
+ if (input.expires && input.expiresIn) {
1417
+ errors.push("pass either expires or expiresIn, not both");
1418
+ return void 0;
1419
+ }
1420
+ if (input.expires) {
1421
+ return input.expires;
1422
+ }
1423
+ if (input.expiresIn) {
1424
+ return parseDurationFromNow(input.expiresIn);
1425
+ }
1426
+ errors.push("expires or expiresIn is required");
1427
+ return void 0;
1428
+ }
1429
+ function parseDurationFromNow(duration) {
1430
+ const match = /^(\d+)([smhd])$/.exec(duration);
1431
+ if (!match) {
1432
+ throw invalidGrantInput([
1433
+ `expiresIn must use a clear duration like '15m', '2h', or '30d'`
1434
+ ]);
1435
+ }
1436
+ const amount = Number(match[1]);
1437
+ if (!Number.isSafeInteger(amount) || amount <= 0) {
1438
+ throw invalidGrantInput(["expiresIn duration must be a positive integer"]);
1439
+ }
1440
+ const unitMs = {
1441
+ s: 1e3,
1442
+ m: 60 * 1e3,
1443
+ h: 60 * 60 * 1e3,
1444
+ d: 24 * 60 * 60 * 1e3
1445
+ };
1446
+ return new Date(Date.now() + amount * unitMs[match[2]]);
1447
+ }
1448
+ function invalidGrantInput(errors) {
1449
+ return new Error(
1450
+ [
1451
+ "Invalid APOA grant input.",
1452
+ ...errors.map((error) => `- ${error}`),
1453
+ "Minimal shape: { principal, agent, service, scopes, expiresIn }"
1454
+ ].join("\n")
1455
+ );
1456
+ }
1316
1457
  export {
1458
+ APOA,
1317
1459
  APOAError,
1318
1460
  AttenuationViolationError,
1319
1461
  ChainVerificationError,