@naylence/runtime 0.3.21 → 0.4.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.
Files changed (85) hide show
  1. package/dist/browser/index.cjs +3144 -1307
  2. package/dist/browser/index.mjs +3116 -1301
  3. package/dist/cjs/naylence/fame/factory-manifest.js +6 -0
  4. package/dist/cjs/naylence/fame/node/node-event-listener.js +4 -0
  5. package/dist/cjs/naylence/fame/security/auth/default-policy-authorizer-factory.js +147 -0
  6. package/dist/cjs/naylence/fame/security/auth/default-policy-authorizer.js +291 -0
  7. package/dist/cjs/naylence/fame/security/auth/oauth2-authorizer-factory.js +7 -0
  8. package/dist/cjs/naylence/fame/security/auth/oauth2-authorizer.js +19 -4
  9. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-definition.js +60 -0
  10. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-factory.js +35 -0
  11. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-source-factory.js +35 -0
  12. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-source.js +2 -0
  13. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy.js +2 -0
  14. package/dist/cjs/naylence/fame/security/auth/policy/basic-authorization-policy-factory.js +99 -0
  15. package/dist/cjs/naylence/fame/security/auth/policy/basic-authorization-policy.js +449 -0
  16. package/dist/cjs/naylence/fame/security/auth/policy/index.js +40 -0
  17. package/dist/cjs/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.js +101 -0
  18. package/dist/cjs/naylence/fame/security/auth/policy/local-file-authorization-policy-source.js +164 -0
  19. package/dist/cjs/naylence/fame/security/auth/policy/pattern-matcher.js +195 -0
  20. package/dist/cjs/naylence/fame/security/auth/policy/scope-matcher.js +169 -0
  21. package/dist/cjs/naylence/fame/security/auth/policy-authorizer.js +2 -0
  22. package/dist/cjs/naylence/fame/security/default-security-manager.js +94 -0
  23. package/dist/cjs/naylence/fame/security/index.js +3 -0
  24. package/dist/cjs/naylence/fame/security/node-security-profile-factory.js +3 -1
  25. package/dist/cjs/naylence/fame/sentinel/router.js +67 -1
  26. package/dist/cjs/naylence/fame/sentinel/sentinel.js +46 -2
  27. package/dist/cjs/naylence/fame/util/register-runtime-factories.js +2 -0
  28. package/dist/cjs/version.js +2 -2
  29. package/dist/esm/naylence/fame/factory-manifest.js +6 -0
  30. package/dist/esm/naylence/fame/node/node-event-listener.js +4 -0
  31. package/dist/esm/naylence/fame/security/auth/default-policy-authorizer-factory.js +110 -0
  32. package/dist/esm/naylence/fame/security/auth/default-policy-authorizer.js +287 -0
  33. package/dist/esm/naylence/fame/security/auth/oauth2-authorizer-factory.js +7 -0
  34. package/dist/esm/naylence/fame/security/auth/oauth2-authorizer.js +19 -4
  35. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-definition.js +57 -0
  36. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-factory.js +31 -0
  37. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-source-factory.js +31 -0
  38. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-source.js +1 -0
  39. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy.js +1 -0
  40. package/dist/esm/naylence/fame/security/auth/policy/basic-authorization-policy-factory.js +62 -0
  41. package/dist/esm/naylence/fame/security/auth/policy/basic-authorization-policy.js +445 -0
  42. package/dist/esm/naylence/fame/security/auth/policy/index.js +20 -0
  43. package/dist/esm/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.js +64 -0
  44. package/dist/esm/naylence/fame/security/auth/policy/local-file-authorization-policy-source.js +127 -0
  45. package/dist/esm/naylence/fame/security/auth/policy/pattern-matcher.js +185 -0
  46. package/dist/esm/naylence/fame/security/auth/policy/scope-matcher.js +162 -0
  47. package/dist/esm/naylence/fame/security/auth/policy-authorizer.js +1 -0
  48. package/dist/esm/naylence/fame/security/default-security-manager.js +94 -0
  49. package/dist/esm/naylence/fame/security/index.js +3 -0
  50. package/dist/esm/naylence/fame/security/node-security-profile-factory.js +2 -0
  51. package/dist/esm/naylence/fame/sentinel/router.js +64 -0
  52. package/dist/esm/naylence/fame/sentinel/sentinel.js +47 -3
  53. package/dist/esm/naylence/fame/util/register-runtime-factories.js +2 -0
  54. package/dist/esm/version.js +2 -2
  55. package/dist/node/index.cjs +3140 -1303
  56. package/dist/node/index.mjs +3116 -1301
  57. package/dist/node/node.cjs +3191 -1338
  58. package/dist/node/node.mjs +3167 -1336
  59. package/dist/types/naylence/fame/factory-manifest.d.ts +1 -1
  60. package/dist/types/naylence/fame/node/node-event-listener.d.ts +31 -0
  61. package/dist/types/naylence/fame/security/auth/authorizer.d.ts +37 -0
  62. package/dist/types/naylence/fame/security/auth/default-policy-authorizer-factory.d.ts +55 -0
  63. package/dist/types/naylence/fame/security/auth/default-policy-authorizer.d.ts +99 -0
  64. package/dist/types/naylence/fame/security/auth/oauth2-authorizer-factory.d.ts +2 -0
  65. package/dist/types/naylence/fame/security/auth/oauth2-authorizer.d.ts +2 -0
  66. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-definition.d.ts +166 -0
  67. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-factory.d.ts +38 -0
  68. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-source-factory.d.ts +38 -0
  69. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-source.d.ts +20 -0
  70. package/dist/types/naylence/fame/security/auth/policy/authorization-policy.d.ts +55 -0
  71. package/dist/types/naylence/fame/security/auth/policy/basic-authorization-policy-factory.d.ts +42 -0
  72. package/dist/types/naylence/fame/security/auth/policy/basic-authorization-policy.d.ts +78 -0
  73. package/dist/types/naylence/fame/security/auth/policy/index.d.ts +19 -0
  74. package/dist/types/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.d.ts +51 -0
  75. package/dist/types/naylence/fame/security/auth/policy/local-file-authorization-policy-source.d.ts +67 -0
  76. package/dist/types/naylence/fame/security/auth/policy/pattern-matcher.d.ts +84 -0
  77. package/dist/types/naylence/fame/security/auth/policy/scope-matcher.d.ts +61 -0
  78. package/dist/types/naylence/fame/security/auth/policy-authorizer.d.ts +12 -0
  79. package/dist/types/naylence/fame/security/default-security-manager.d.ts +22 -0
  80. package/dist/types/naylence/fame/security/index.d.ts +2 -0
  81. package/dist/types/naylence/fame/security/node-security-profile-factory.d.ts +1 -0
  82. package/dist/types/naylence/fame/sentinel/router.d.ts +68 -0
  83. package/dist/types/naylence/fame/sentinel/sentinel.d.ts +16 -0
  84. package/dist/types/version.d.ts +1 -1
  85. package/package.json +1 -1
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.LocalFileAuthorizationPolicySourceFactory = exports.FACTORY_META = void 0;
37
+ const lazy_import_js_1 = require("../../../util/lazy-import.js");
38
+ const authorization_policy_source_factory_js_1 = require("./authorization-policy-source-factory.js");
39
+ let localFileModulePromise = null;
40
+ async function getLocalFileModule() {
41
+ if (!localFileModulePromise) {
42
+ localFileModulePromise = (0, lazy_import_js_1.safeImport)(() => Promise.resolve().then(() => __importStar(require('./local-file-authorization-policy-source.js'))), 'local-file-authorization-policy-source');
43
+ }
44
+ return localFileModulePromise;
45
+ }
46
+ function normalizeConfig(config) {
47
+ if (!config) {
48
+ throw new Error('LocalFileAuthorizationPolicySourceFactory requires a configuration with a path');
49
+ }
50
+ const candidate = config;
51
+ const path = candidate.path;
52
+ if (typeof path !== 'string' || path.trim().length === 0) {
53
+ throw new Error('LocalFileAuthorizationPolicySourceConfig requires a non-empty path');
54
+ }
55
+ const format = candidate.format;
56
+ if (format !== undefined && !['yaml', 'json', 'auto'].includes(format)) {
57
+ throw new Error(`Invalid format "${String(format)}". Must be "yaml", "json", or "auto"`);
58
+ }
59
+ const policyFactory = candidate.policyFactory;
60
+ return {
61
+ path: path.trim(),
62
+ format: format ?? 'auto',
63
+ policyFactory,
64
+ };
65
+ }
66
+ /**
67
+ * Factory metadata for registration.
68
+ */
69
+ exports.FACTORY_META = {
70
+ base: authorization_policy_source_factory_js_1.AUTHORIZATION_POLICY_SOURCE_FACTORY_BASE_TYPE,
71
+ key: 'LocalFileAuthorizationPolicySource',
72
+ };
73
+ /**
74
+ * Factory for creating LocalFileAuthorizationPolicySource instances.
75
+ *
76
+ * This factory uses lazy loading to avoid pulling in Node.js-specific
77
+ * code (filesystem operations) in browser environments.
78
+ */
79
+ class LocalFileAuthorizationPolicySourceFactory extends authorization_policy_source_factory_js_1.AuthorizationPolicySourceFactory {
80
+ constructor() {
81
+ super(...arguments);
82
+ this.type = 'LocalFileAuthorizationPolicySource';
83
+ }
84
+ /**
85
+ * Creates a LocalFileAuthorizationPolicySource from the given configuration.
86
+ *
87
+ * @param config - Configuration specifying the policy file path and options
88
+ * @returns The created policy source
89
+ */
90
+ async create(config) {
91
+ const normalized = normalizeConfig(config);
92
+ const { LocalFileAuthorizationPolicySource } = await getLocalFileModule();
93
+ return new LocalFileAuthorizationPolicySource({
94
+ path: normalized.path,
95
+ format: normalized.format,
96
+ policyFactory: normalized.policyFactory,
97
+ });
98
+ }
99
+ }
100
+ exports.LocalFileAuthorizationPolicySourceFactory = LocalFileAuthorizationPolicySourceFactory;
101
+ exports.default = LocalFileAuthorizationPolicySourceFactory;
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.LocalFileAuthorizationPolicySource = void 0;
37
+ const yaml_1 = require("yaml");
38
+ const logging_js_1 = require("../../../util/logging.js");
39
+ const authorization_policy_factory_js_1 = require("./authorization-policy-factory.js");
40
+ const logger = (0, logging_js_1.getLogger)('naylence.fame.security.auth.policy.local_file_authorization_policy_source');
41
+ function isPlainObject(value) {
42
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
43
+ }
44
+ function parseJson(content) {
45
+ const parsed = JSON.parse(content);
46
+ if (!isPlainObject(parsed)) {
47
+ throw new Error('Parsed JSON policy must be an object');
48
+ }
49
+ return parsed;
50
+ }
51
+ function parseYamlContent(content) {
52
+ const parsed = (0, yaml_1.parse)(content ?? '');
53
+ if (parsed == null) {
54
+ return {};
55
+ }
56
+ if (!isPlainObject(parsed)) {
57
+ throw new Error('Parsed YAML policy must be an object');
58
+ }
59
+ return parsed;
60
+ }
61
+ function detectFormat(filePath) {
62
+ const lower = filePath.toLowerCase();
63
+ if (lower.endsWith('.yaml') || lower.endsWith('.yml')) {
64
+ return 'yaml';
65
+ }
66
+ if (lower.endsWith('.json')) {
67
+ return 'json';
68
+ }
69
+ // Default to YAML for unknown extensions
70
+ return 'yaml';
71
+ }
72
+ /**
73
+ * An authorization policy source that loads policy definitions from a local file.
74
+ *
75
+ * Supports YAML and JSON formats. The file must contain a valid policy
76
+ * configuration object that can be used to create an AuthorizationPolicy
77
+ * via the factory system.
78
+ *
79
+ * This is a Node.js-only implementation that uses the filesystem.
80
+ */
81
+ class LocalFileAuthorizationPolicySource {
82
+ constructor(options) {
83
+ this.cachedPolicy = null;
84
+ this.path = options.path;
85
+ this.format = options.format ?? 'auto';
86
+ this.policyFactoryConfig = options.policyFactory;
87
+ }
88
+ /**
89
+ * Loads the authorization policy from the configured file.
90
+ *
91
+ * The file is read and parsed according to the configured format.
92
+ * The parsed content is then used to create an AuthorizationPolicy
93
+ * via the factory system.
94
+ *
95
+ * @returns The loaded authorization policy
96
+ */
97
+ async loadPolicy() {
98
+ // Return cached policy if available
99
+ if (this.cachedPolicy) {
100
+ return this.cachedPolicy;
101
+ }
102
+ logger.debug('loading_policy_from_file', { path: this.path });
103
+ // Dynamic import of fs for Node.js
104
+ const fs = await Promise.resolve().then(() => __importStar(require('node:fs/promises')));
105
+ // Read the file
106
+ const content = await fs.readFile(this.path, 'utf-8');
107
+ // Determine format
108
+ const effectiveFormat = this.format === 'auto' ? detectFormat(this.path) : this.format;
109
+ // Parse the content
110
+ let policyDefinition;
111
+ if (effectiveFormat === 'json') {
112
+ policyDefinition = parseJson(content);
113
+ }
114
+ else {
115
+ policyDefinition = parseYamlContent(content);
116
+ }
117
+ logger.debug('parsed_policy_definition', {
118
+ path: this.path,
119
+ format: effectiveFormat,
120
+ hasType: 'type' in policyDefinition,
121
+ });
122
+ // Determine the factory configuration to use
123
+ const factoryConfig = this.policyFactoryConfig ?? policyDefinition;
124
+ // Ensure we have a type field for the factory
125
+ if (!('type' in factoryConfig) || typeof factoryConfig.type !== 'string') {
126
+ throw new Error(`Policy definition at ${this.path} must have a 'type' field, ` +
127
+ `or policyFactory config must be provided`);
128
+ }
129
+ // Build the factory config with the policy definition
130
+ // The file content IS the policy definition, so we extract the type
131
+ // and wrap the remaining content as the policyDefinition
132
+ const { type, ...restOfFile } = policyDefinition;
133
+ const mergedConfig = this.policyFactoryConfig != null
134
+ ? { ...this.policyFactoryConfig, policyDefinition }
135
+ : { type: factoryConfig.type, policyDefinition: restOfFile };
136
+ // Create the policy using the factory system
137
+ const policy = await authorization_policy_factory_js_1.AuthorizationPolicyFactory.createAuthorizationPolicy(mergedConfig);
138
+ if (!policy) {
139
+ throw new Error(`Failed to create authorization policy from ${this.path}`);
140
+ }
141
+ this.cachedPolicy = policy;
142
+ logger.info('loaded_policy_from_file', {
143
+ path: this.path,
144
+ policyType: factoryConfig.type,
145
+ });
146
+ return policy;
147
+ }
148
+ /**
149
+ * Clears the cached policy, forcing a reload on the next loadPolicy() call.
150
+ */
151
+ clearCache() {
152
+ this.cachedPolicy = null;
153
+ }
154
+ /**
155
+ * Reloads the policy from the file, clearing any cached version.
156
+ *
157
+ * @returns The reloaded authorization policy
158
+ */
159
+ async reloadPolicy() {
160
+ this.clearCache();
161
+ return this.loadPolicy();
162
+ }
163
+ }
164
+ exports.LocalFileAuthorizationPolicySource = LocalFileAuthorizationPolicySource;
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ /**
3
+ * Pattern matching utilities for authorization policies.
4
+ *
5
+ * Supports:
6
+ * - Glob patterns: `*` (single segment), `**` (any depth), `?` (single char)
7
+ * - Regex patterns: patterns starting with `^` (for advanced/BSL use only)
8
+ *
9
+ * The OSS/basic policy uses glob-only matching via `compileGlobPattern()`.
10
+ * The advanced/BSL policy may use `compilePattern()` which interprets `^` as regex.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.isRegexPattern = isRegexPattern;
14
+ exports.assertNotRegexPattern = assertNotRegexPattern;
15
+ exports.compilePattern = compilePattern;
16
+ exports.compileGlobPattern = compileGlobPattern;
17
+ exports.getCompiledPattern = getCompiledPattern;
18
+ exports.getCompiledGlobPattern = getCompiledGlobPattern;
19
+ exports.matchPattern = matchPattern;
20
+ exports.clearPatternCache = clearPatternCache;
21
+ /**
22
+ * Checks if a pattern string is a regex pattern.
23
+ * Regex patterns start with `^`.
24
+ */
25
+ function isRegexPattern(pattern) {
26
+ return pattern.startsWith('^');
27
+ }
28
+ /**
29
+ * Asserts that a pattern is not a regex pattern.
30
+ * Throws an error if the pattern starts with `^`.
31
+ *
32
+ * Use this in OSS/basic policy to reject regex patterns.
33
+ *
34
+ * @param pattern - The pattern to check
35
+ * @param context - Optional context for the error message (e.g., "address", "scope")
36
+ * @throws Error if the pattern is a regex pattern
37
+ */
38
+ function assertNotRegexPattern(pattern, context) {
39
+ if (pattern.startsWith('^')) {
40
+ const contextStr = context ? ` in ${context}` : '';
41
+ throw new Error(`Regex patterns are not supported${contextStr} in OSS/basic policy. ` +
42
+ `Pattern "${pattern}" starts with '^'. Use glob patterns instead.`);
43
+ }
44
+ }
45
+ /**
46
+ * Escapes special regex characters in a string.
47
+ */
48
+ function escapeRegex(str) {
49
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
50
+ }
51
+ /**
52
+ * Converts a glob pattern to a regex pattern.
53
+ *
54
+ * Glob syntax:
55
+ * - `*` matches a single segment (no dots)
56
+ * - `**` matches any number of segments (including zero)
57
+ * - Other characters are matched literally
58
+ *
59
+ * @param glob - The glob pattern to convert
60
+ * @returns A regex pattern string (without anchors)
61
+ */
62
+ function globToRegex(glob) {
63
+ const parts = [];
64
+ let i = 0;
65
+ while (i < glob.length) {
66
+ if (glob[i] === '*') {
67
+ if (glob[i + 1] === '*') {
68
+ // `**` matches any characters (including dots)
69
+ parts.push('.*');
70
+ i += 2;
71
+ }
72
+ else {
73
+ // `*` matches any characters except dots (single segment)
74
+ parts.push('[^.]*');
75
+ i += 1;
76
+ }
77
+ }
78
+ else if (glob[i] === '?') {
79
+ // `?` matches a single character (not a dot)
80
+ parts.push('[^.]');
81
+ i += 1;
82
+ }
83
+ else {
84
+ // Escape and add literal character
85
+ parts.push(escapeRegex(glob[i]));
86
+ i += 1;
87
+ }
88
+ }
89
+ return parts.join('');
90
+ }
91
+ /**
92
+ * Compiles a pattern string into an efficient matcher.
93
+ *
94
+ * @param pattern - Glob pattern or regex (starting with `^`)
95
+ * @returns A compiled pattern object
96
+ * @throws Error if the regex pattern is invalid
97
+ */
98
+ function compilePattern(pattern) {
99
+ if (isRegexPattern(pattern)) {
100
+ // Regex pattern - compile directly
101
+ const regex = new RegExp(pattern);
102
+ return {
103
+ source: pattern,
104
+ isRegex: true,
105
+ match: (value) => regex.test(value),
106
+ };
107
+ }
108
+ // Glob pattern - convert to regex with anchors
109
+ const regexStr = `^${globToRegex(pattern)}$`;
110
+ const regex = new RegExp(regexStr);
111
+ return {
112
+ source: pattern,
113
+ isRegex: false,
114
+ match: (value) => regex.test(value),
115
+ };
116
+ }
117
+ /**
118
+ * Compiles a pattern string as a glob pattern only (no regex interpretation).
119
+ *
120
+ * This is the preferred method for OSS/basic policy evaluation.
121
+ * Patterns starting with `^` are rejected with an error.
122
+ *
123
+ * @param pattern - Glob pattern (regex patterns rejected)
124
+ * @param context - Optional context for error messages
125
+ * @returns A compiled pattern object
126
+ * @throws Error if pattern starts with `^` (regex attempt)
127
+ */
128
+ function compileGlobPattern(pattern, context) {
129
+ // Reject regex patterns in OSS/basic policy
130
+ assertNotRegexPattern(pattern, context);
131
+ // Convert glob to regex with anchors
132
+ const regexStr = `^${globToRegex(pattern)}$`;
133
+ const regex = new RegExp(regexStr);
134
+ return {
135
+ source: pattern,
136
+ isRegex: false,
137
+ match: (value) => regex.test(value),
138
+ };
139
+ }
140
+ /**
141
+ * Cache for compiled patterns to avoid recompilation.
142
+ */
143
+ const patternCache = new Map();
144
+ /**
145
+ * Cache for glob-only compiled patterns.
146
+ */
147
+ const globPatternCache = new Map();
148
+ /**
149
+ * Gets or compiles a pattern, with caching.
150
+ *
151
+ * @param pattern - Glob pattern or regex
152
+ * @returns A compiled pattern object
153
+ */
154
+ function getCompiledPattern(pattern) {
155
+ let compiled = patternCache.get(pattern);
156
+ if (!compiled) {
157
+ compiled = compilePattern(pattern);
158
+ patternCache.set(pattern, compiled);
159
+ }
160
+ return compiled;
161
+ }
162
+ /**
163
+ * Gets or compiles a glob-only pattern, with caching.
164
+ *
165
+ * This is the preferred method for OSS/basic policy evaluation.
166
+ * Patterns are always treated as globs, never regex.
167
+ *
168
+ * @param pattern - Glob pattern (never interpreted as regex)
169
+ * @returns A compiled pattern object
170
+ */
171
+ function getCompiledGlobPattern(pattern) {
172
+ let compiled = globPatternCache.get(pattern);
173
+ if (!compiled) {
174
+ compiled = compileGlobPattern(pattern);
175
+ globPatternCache.set(pattern, compiled);
176
+ }
177
+ return compiled;
178
+ }
179
+ /**
180
+ * Matches a value against a pattern string.
181
+ *
182
+ * @param pattern - Glob pattern or regex (starting with `^`)
183
+ * @param value - The value to match
184
+ * @returns True if the value matches the pattern
185
+ */
186
+ function matchPattern(pattern, value) {
187
+ return getCompiledPattern(pattern).match(value);
188
+ }
189
+ /**
190
+ * Clears the pattern cache.
191
+ * Useful for testing or when memory is a concern.
192
+ */
193
+ function clearPatternCache() {
194
+ patternCache.clear();
195
+ }
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ /**
3
+ * Scope matching utilities for authorization policies.
4
+ *
5
+ * Supports:
6
+ * - Simple string patterns (glob only in OSS/basic policy)
7
+ * - Logical operators: any_of, all_of, none_of
8
+ * - Recursive nesting with depth limits
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.normalizeScopeRequirement = normalizeScopeRequirement;
12
+ exports.evaluateNormalizedScopeRequirement = evaluateNormalizedScopeRequirement;
13
+ exports.evaluateScopeRequirement = evaluateScopeRequirement;
14
+ exports.compileScopeRequirement = compileScopeRequirement;
15
+ exports.compileGlobOnlyScopeRequirement = compileGlobOnlyScopeRequirement;
16
+ const authorization_policy_definition_js_1 = require("./authorization-policy-definition.js");
17
+ const pattern_matcher_js_1 = require("./pattern-matcher.js");
18
+ /**
19
+ * Checks if any of the granted scopes match the given pattern.
20
+ */
21
+ function anyScopeMatchesPattern(grantedScopes, pattern) {
22
+ return grantedScopes.some((scope) => (0, pattern_matcher_js_1.matchPattern)(pattern, scope));
23
+ }
24
+ /**
25
+ * Normalizes a scope requirement into a typed structure.
26
+ *
27
+ * @param requirement - The scope requirement to normalize
28
+ * @param depth - Current nesting depth (for recursion limit)
29
+ * @returns Normalized scope requirement
30
+ * @throws Error if nesting exceeds maximum depth
31
+ */
32
+ function normalizeScopeRequirement(requirement, depth = 0) {
33
+ if (depth > authorization_policy_definition_js_1.MAX_SCOPE_NESTING_DEPTH) {
34
+ throw new Error(`Scope requirement nesting exceeds maximum depth of ${authorization_policy_definition_js_1.MAX_SCOPE_NESTING_DEPTH}`);
35
+ }
36
+ // Simple string pattern
37
+ if (typeof requirement === 'string') {
38
+ return { type: 'pattern', pattern: requirement };
39
+ }
40
+ // Object with logical operator
41
+ if (typeof requirement !== 'object' || requirement === null) {
42
+ throw new Error(`Invalid scope requirement: ${String(requirement)}`);
43
+ }
44
+ const keys = Object.keys(requirement);
45
+ if (keys.length !== 1) {
46
+ throw new Error(`Scope requirement object must have exactly one key (any_of, all_of, or none_of), got: ${keys.join(', ')}`);
47
+ }
48
+ const key = keys[0];
49
+ const value = requirement[key];
50
+ if (!Array.isArray(value)) {
51
+ throw new Error(`Scope requirement "${key}" must have an array value, got: ${typeof value}`);
52
+ }
53
+ const nested = value.map((item) => normalizeScopeRequirement(item, depth + 1));
54
+ switch (key) {
55
+ case 'any_of':
56
+ return { type: 'any_of', requirements: nested };
57
+ case 'all_of':
58
+ return { type: 'all_of', requirements: nested };
59
+ case 'none_of':
60
+ return { type: 'none_of', requirements: nested };
61
+ default:
62
+ throw new Error(`Unknown scope requirement operator: "${key}". Expected any_of, all_of, or none_of`);
63
+ }
64
+ }
65
+ /**
66
+ * Evaluates a normalized scope requirement against granted scopes.
67
+ *
68
+ * @param requirement - The normalized scope requirement
69
+ * @param grantedScopes - The scopes granted to the principal
70
+ * @returns True if the requirement is satisfied
71
+ */
72
+ function evaluateNormalizedScopeRequirement(requirement, grantedScopes) {
73
+ switch (requirement.type) {
74
+ case 'pattern':
75
+ return anyScopeMatchesPattern(grantedScopes, requirement.pattern);
76
+ case 'any_of':
77
+ return requirement.requirements.some((req) => evaluateNormalizedScopeRequirement(req, grantedScopes));
78
+ case 'all_of':
79
+ return requirement.requirements.every((req) => evaluateNormalizedScopeRequirement(req, grantedScopes));
80
+ case 'none_of':
81
+ return !requirement.requirements.some((req) => evaluateNormalizedScopeRequirement(req, grantedScopes));
82
+ default:
83
+ // Exhaustive check
84
+ throw new Error(`Unknown scope requirement type: ${requirement.type}`);
85
+ }
86
+ }
87
+ /**
88
+ * Evaluates a scope requirement against granted scopes.
89
+ *
90
+ * This is the main entry point for scope matching.
91
+ *
92
+ * @param requirement - The scope requirement (string or object)
93
+ * @param grantedScopes - The scopes granted to the principal
94
+ * @returns True if the requirement is satisfied
95
+ */
96
+ function evaluateScopeRequirement(requirement, grantedScopes) {
97
+ const normalized = normalizeScopeRequirement(requirement);
98
+ return evaluateNormalizedScopeRequirement(normalized, grantedScopes);
99
+ }
100
+ /**
101
+ * Pre-compiles a scope requirement for efficient repeated evaluation.
102
+ *
103
+ * @param requirement - The scope requirement to compile
104
+ * @returns A function that evaluates the requirement against granted scopes
105
+ */
106
+ function compileScopeRequirement(requirement) {
107
+ const normalized = normalizeScopeRequirement(requirement);
108
+ return (grantedScopes) => evaluateNormalizedScopeRequirement(normalized, grantedScopes);
109
+ }
110
+ /**
111
+ * Pre-compiles a scope requirement for OSS/basic policy (glob-only, no regex).
112
+ *
113
+ * This version rejects patterns starting with `^` at compile time.
114
+ *
115
+ * @param requirement - The scope requirement to compile
116
+ * @param ruleId - Rule ID for error messages
117
+ * @returns A compiled scope requirement
118
+ * @throws Error if any pattern starts with `^` (regex attempt)
119
+ */
120
+ function compileGlobOnlyScopeRequirement(requirement, ruleId) {
121
+ const context = `scope in rule "${ruleId}"`;
122
+ // Compile the requirement, pre-compiling all patterns as globs
123
+ const compiled = compileGlobOnlyNormalized(normalizeScopeRequirement(requirement), context);
124
+ return {
125
+ evaluate: (grantedScopes) => evaluateCompiledScope(compiled, grantedScopes),
126
+ };
127
+ }
128
+ /**
129
+ * Compiles a normalized scope requirement into efficient matchers (glob-only).
130
+ */
131
+ function compileGlobOnlyNormalized(requirement, context) {
132
+ switch (requirement.type) {
133
+ case 'pattern':
134
+ return {
135
+ type: 'pattern',
136
+ matcher: (0, pattern_matcher_js_1.compileGlobPattern)(requirement.pattern, context),
137
+ };
138
+ case 'any_of':
139
+ return {
140
+ type: 'any_of',
141
+ requirements: requirement.requirements.map((r) => compileGlobOnlyNormalized(r, context)),
142
+ };
143
+ case 'all_of':
144
+ return {
145
+ type: 'all_of',
146
+ requirements: requirement.requirements.map((r) => compileGlobOnlyNormalized(r, context)),
147
+ };
148
+ case 'none_of':
149
+ return {
150
+ type: 'none_of',
151
+ requirements: requirement.requirements.map((r) => compileGlobOnlyNormalized(r, context)),
152
+ };
153
+ }
154
+ }
155
+ /**
156
+ * Evaluates a compiled scope node against granted scopes.
157
+ */
158
+ function evaluateCompiledScope(node, grantedScopes) {
159
+ switch (node.type) {
160
+ case 'pattern':
161
+ return grantedScopes.some((scope) => node.matcher.match(scope));
162
+ case 'any_of':
163
+ return node.requirements.some((r) => evaluateCompiledScope(r, grantedScopes));
164
+ case 'all_of':
165
+ return node.requirements.every((r) => evaluateCompiledScope(r, grantedScopes));
166
+ case 'none_of':
167
+ return !node.requirements.some((r) => evaluateCompiledScope(r, grantedScopes));
168
+ }
169
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });