@redocly/realm 0.129.0-next.5 → 0.129.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 (31) hide show
  1. package/CHANGELOG.md +58 -1
  2. package/dist/constants/common.d.ts +1 -0
  3. package/dist/constants/common.js +1 -1
  4. package/dist/server/plugins/catalog-entities/database/constants/relation-normalization.d.ts +3 -0
  5. package/dist/server/plugins/catalog-entities/database/constants/relation-normalization.js +1 -0
  6. package/dist/server/plugins/catalog-entities/database/mappers/create-entity-relation-db-record-from-dto.js +1 -1
  7. package/dist/server/plugins/catalog-entities/database/mappers/create-entity-relation-db-record-from-file-schema.js +1 -1
  8. package/dist/server/plugins/catalog-entities/database/repositories/local/catalog-entities-bff-repository.d.ts +14 -0
  9. package/dist/server/plugins/catalog-entities/database/repositories/local/catalog-entities-bff-repository.js +112 -0
  10. package/dist/server/plugins/catalog-entities/database/repositories/local/catalog-entities-local-read-repository.js +12 -130
  11. package/dist/server/plugins/catalog-entities/database/repositories/local/catalog-entities-local-write-repository.js +1 -1
  12. package/dist/server/plugins/catalog-entities/utils/normalize-relation.d.ts +77 -0
  13. package/dist/server/plugins/catalog-entities/utils/normalize-relation.js +1 -0
  14. package/dist/server/plugins/config-parser/format-error.js +13 -5
  15. package/dist/server/plugins/config-parser/loaders/utils/read-and-validate-config.js +1 -1
  16. package/dist/server/providers/database/databases/catalog-sqlite/migrations/0003_catalog_versions_and_revisions_relations.sql +12 -6
  17. package/dist/server/providers/database/databases/catalog-sqlite/migrations/0004_normalize_relation_types.sql +147 -0
  18. package/dist/server/providers/database/databases/catalog-sqlite/migrations/meta/0004_snapshot.json +392 -0
  19. package/dist/server/providers/database/databases/catalog-sqlite/migrations/meta/_journal.json +7 -0
  20. package/dist/server/providers/database/databases/sqld-sqlite/migrations/0006_catalog-versions-and-revisions-relations.sql +12 -6
  21. package/dist/server/providers/database/pagination/filter.d.ts +1 -0
  22. package/dist/server/providers/database/pagination/filter.js +1 -1
  23. package/dist/server/web-server/auth.js +2 -2
  24. package/dist/server/web-server/routes/auth.d.ts +1 -0
  25. package/dist/server/web-server/routes/auth.js +1 -1
  26. package/dist/server/web-server/routes/index.js +1 -1
  27. package/dist/server/web-server/routes/mcp-oauth.d.ts +10 -0
  28. package/dist/server/web-server/routes/mcp-oauth.js +1 -1
  29. package/dist/server/web-server/utils/get-request-origin.d.ts +3 -0
  30. package/dist/server/web-server/utils/get-request-origin.js +1 -0
  31. package/package.json +9 -9
@@ -0,0 +1,392 @@
1
+ {
2
+ "version": "6",
3
+ "dialect": "sqlite",
4
+ "id": "a1b2c3d4-e5f6-4789-a012-3456789abcde",
5
+ "prevId": "81397c74-6950-4f46-a595-b92bf6bded70",
6
+ "tables": {
7
+ "entities_relations": {
8
+ "name": "entities_relations",
9
+ "columns": {
10
+ "id": {
11
+ "name": "id",
12
+ "type": "text",
13
+ "primaryKey": true,
14
+ "notNull": true,
15
+ "autoincrement": false
16
+ },
17
+ "organization_id": {
18
+ "name": "organization_id",
19
+ "type": "text",
20
+ "primaryKey": false,
21
+ "notNull": true,
22
+ "autoincrement": false
23
+ },
24
+ "project_id": {
25
+ "name": "project_id",
26
+ "type": "text",
27
+ "primaryKey": false,
28
+ "notNull": true,
29
+ "autoincrement": false
30
+ },
31
+ "source_key": {
32
+ "name": "source_key",
33
+ "type": "text",
34
+ "primaryKey": false,
35
+ "notNull": true,
36
+ "autoincrement": false
37
+ },
38
+ "source_version": {
39
+ "name": "source_version",
40
+ "type": "text",
41
+ "primaryKey": false,
42
+ "notNull": true,
43
+ "autoincrement": false,
44
+ "default": "''"
45
+ },
46
+ "source_revision": {
47
+ "name": "source_revision",
48
+ "type": "text",
49
+ "primaryKey": false,
50
+ "notNull": true,
51
+ "autoincrement": false,
52
+ "default": "''"
53
+ },
54
+ "source_to_target_relation": {
55
+ "name": "source_to_target_relation",
56
+ "type": "text",
57
+ "primaryKey": false,
58
+ "notNull": true,
59
+ "autoincrement": false
60
+ },
61
+ "target_key": {
62
+ "name": "target_key",
63
+ "type": "text",
64
+ "primaryKey": false,
65
+ "notNull": true,
66
+ "autoincrement": false
67
+ },
68
+ "target_version": {
69
+ "name": "target_version",
70
+ "type": "text",
71
+ "primaryKey": false,
72
+ "notNull": true,
73
+ "autoincrement": false,
74
+ "default": "''"
75
+ },
76
+ "target_revision": {
77
+ "name": "target_revision",
78
+ "type": "text",
79
+ "primaryKey": false,
80
+ "notNull": true,
81
+ "autoincrement": false,
82
+ "default": "''"
83
+ },
84
+ "target_to_source_relation": {
85
+ "name": "target_to_source_relation",
86
+ "type": "text",
87
+ "primaryKey": false,
88
+ "notNull": true,
89
+ "autoincrement": false
90
+ },
91
+ "source_file": {
92
+ "name": "source_file",
93
+ "type": "text",
94
+ "primaryKey": false,
95
+ "notNull": false,
96
+ "autoincrement": false
97
+ },
98
+ "file_hash": {
99
+ "name": "file_hash",
100
+ "type": "text",
101
+ "primaryKey": false,
102
+ "notNull": false,
103
+ "autoincrement": false
104
+ },
105
+ "is_deleted": {
106
+ "name": "is_deleted",
107
+ "type": "integer",
108
+ "primaryKey": false,
109
+ "notNull": false,
110
+ "autoincrement": false,
111
+ "default": false
112
+ },
113
+ "created_at": {
114
+ "name": "created_at",
115
+ "type": "text",
116
+ "primaryKey": false,
117
+ "notNull": true,
118
+ "autoincrement": false
119
+ },
120
+ "updated_at": {
121
+ "name": "updated_at",
122
+ "type": "text",
123
+ "primaryKey": false,
124
+ "notNull": true,
125
+ "autoincrement": false
126
+ }
127
+ },
128
+ "indexes": {
129
+ "idx_entities_relations_source_key": {
130
+ "name": "idx_entities_relations_source_key",
131
+ "columns": ["source_key", "is_deleted"],
132
+ "isUnique": false
133
+ },
134
+ "idx_entities_relations_target_key": {
135
+ "name": "idx_entities_relations_target_key",
136
+ "columns": ["target_key", "is_deleted"],
137
+ "isUnique": false
138
+ },
139
+ "idx_entities_relations_source_target": {
140
+ "name": "idx_entities_relations_source_target",
141
+ "columns": ["source_to_target_relation"],
142
+ "isUnique": false
143
+ },
144
+ "idx_entities_relations_target_source": {
145
+ "name": "idx_entities_relations_target_source",
146
+ "columns": ["target_to_source_relation"],
147
+ "isUnique": false
148
+ },
149
+ "idx_entities_relations_unique": {
150
+ "name": "idx_entities_relations_unique",
151
+ "columns": [
152
+ "source_key",
153
+ "target_key",
154
+ "source_version",
155
+ "target_version",
156
+ "source_revision",
157
+ "target_revision"
158
+ ],
159
+ "isUnique": true
160
+ }
161
+ },
162
+ "foreignKeys": {},
163
+ "compositePrimaryKeys": {},
164
+ "uniqueConstraints": {},
165
+ "checkConstraints": {}
166
+ },
167
+ "entities": {
168
+ "name": "entities",
169
+ "columns": {
170
+ "id": {
171
+ "name": "id",
172
+ "type": "text",
173
+ "primaryKey": true,
174
+ "notNull": true,
175
+ "autoincrement": false
176
+ },
177
+ "organization_id": {
178
+ "name": "organization_id",
179
+ "type": "text",
180
+ "primaryKey": false,
181
+ "notNull": true,
182
+ "autoincrement": false
183
+ },
184
+ "project_id": {
185
+ "name": "project_id",
186
+ "type": "text",
187
+ "primaryKey": false,
188
+ "notNull": true,
189
+ "autoincrement": false
190
+ },
191
+ "key": {
192
+ "name": "key",
193
+ "type": "text",
194
+ "primaryKey": false,
195
+ "notNull": true,
196
+ "autoincrement": false
197
+ },
198
+ "type": {
199
+ "name": "type",
200
+ "type": "text",
201
+ "primaryKey": false,
202
+ "notNull": true,
203
+ "autoincrement": false
204
+ },
205
+ "title": {
206
+ "name": "title",
207
+ "type": "text",
208
+ "primaryKey": false,
209
+ "notNull": true,
210
+ "autoincrement": false
211
+ },
212
+ "summary": {
213
+ "name": "summary",
214
+ "type": "text",
215
+ "primaryKey": false,
216
+ "notNull": false,
217
+ "autoincrement": false
218
+ },
219
+ "tags": {
220
+ "name": "tags",
221
+ "type": "text",
222
+ "primaryKey": false,
223
+ "notNull": false,
224
+ "autoincrement": false
225
+ },
226
+ "metadata": {
227
+ "name": "metadata",
228
+ "type": "text",
229
+ "primaryKey": false,
230
+ "notNull": false,
231
+ "autoincrement": false
232
+ },
233
+ "git": {
234
+ "name": "git",
235
+ "type": "text",
236
+ "primaryKey": false,
237
+ "notNull": false,
238
+ "autoincrement": false
239
+ },
240
+ "contact": {
241
+ "name": "contact",
242
+ "type": "text",
243
+ "primaryKey": false,
244
+ "notNull": false,
245
+ "autoincrement": false
246
+ },
247
+ "links": {
248
+ "name": "links",
249
+ "type": "text",
250
+ "primaryKey": false,
251
+ "notNull": false,
252
+ "autoincrement": false
253
+ },
254
+ "created_at": {
255
+ "name": "created_at",
256
+ "type": "text",
257
+ "primaryKey": false,
258
+ "notNull": true,
259
+ "autoincrement": false
260
+ },
261
+ "updated_at": {
262
+ "name": "updated_at",
263
+ "type": "text",
264
+ "primaryKey": false,
265
+ "notNull": true,
266
+ "autoincrement": false
267
+ },
268
+ "source": {
269
+ "name": "source",
270
+ "type": "text",
271
+ "primaryKey": false,
272
+ "notNull": false,
273
+ "autoincrement": false,
274
+ "default": "'file'"
275
+ },
276
+ "source_file": {
277
+ "name": "source_file",
278
+ "type": "text",
279
+ "primaryKey": false,
280
+ "notNull": false,
281
+ "autoincrement": false
282
+ },
283
+ "file_hash": {
284
+ "name": "file_hash",
285
+ "type": "text",
286
+ "primaryKey": false,
287
+ "notNull": false,
288
+ "autoincrement": false
289
+ },
290
+ "version": {
291
+ "name": "version",
292
+ "type": "text",
293
+ "primaryKey": false,
294
+ "notNull": true,
295
+ "autoincrement": false,
296
+ "default": "'not_specified_version'"
297
+ },
298
+ "revision": {
299
+ "name": "revision",
300
+ "type": "text",
301
+ "primaryKey": false,
302
+ "notNull": true,
303
+ "autoincrement": false
304
+ },
305
+ "hash": {
306
+ "name": "hash",
307
+ "type": "text",
308
+ "primaryKey": false,
309
+ "notNull": false,
310
+ "autoincrement": false
311
+ },
312
+ "is_current": {
313
+ "name": "is_current",
314
+ "type": "integer",
315
+ "primaryKey": false,
316
+ "notNull": false,
317
+ "autoincrement": false,
318
+ "default": true
319
+ },
320
+ "is_default_version": {
321
+ "name": "is_default_version",
322
+ "type": "integer",
323
+ "primaryKey": false,
324
+ "notNull": false,
325
+ "autoincrement": false,
326
+ "default": false
327
+ },
328
+ "is_deleted": {
329
+ "name": "is_deleted",
330
+ "type": "integer",
331
+ "primaryKey": false,
332
+ "notNull": false,
333
+ "autoincrement": false,
334
+ "default": false
335
+ },
336
+ "scorecards_status": {
337
+ "name": "scorecards_status",
338
+ "type": "text",
339
+ "primaryKey": false,
340
+ "notNull": false,
341
+ "autoincrement": false
342
+ }
343
+ },
344
+ "indexes": {
345
+ "idx_entities_type": {
346
+ "name": "idx_entities_type",
347
+ "columns": ["type"],
348
+ "isUnique": false
349
+ },
350
+ "idx_entities_hash": {
351
+ "name": "idx_entities_hash",
352
+ "columns": ["hash"],
353
+ "isUnique": false
354
+ },
355
+ "idx_entities_key_source_created_at": {
356
+ "name": "idx_entities_key_source_created_at",
357
+ "columns": ["key", "created_at"],
358
+ "isUnique": false
359
+ },
360
+ "idx_entities_key_source_is_current": {
361
+ "name": "idx_entities_key_source_is_current",
362
+ "columns": ["key", "is_current", "is_deleted"],
363
+ "isUnique": false
364
+ },
365
+ "idx_entities_key_source_is_default": {
366
+ "name": "idx_entities_key_source_is_default",
367
+ "columns": ["key", "is_default_version"],
368
+ "isUnique": false
369
+ },
370
+ "idx_entities_key_source": {
371
+ "name": "idx_entities_key_source",
372
+ "columns": ["key", "source", "revision", "version"],
373
+ "isUnique": true
374
+ }
375
+ },
376
+ "foreignKeys": {},
377
+ "compositePrimaryKeys": {},
378
+ "uniqueConstraints": {},
379
+ "checkConstraints": {}
380
+ }
381
+ },
382
+ "views": {},
383
+ "enums": {},
384
+ "_meta": {
385
+ "schemas": {},
386
+ "tables": {},
387
+ "columns": {}
388
+ },
389
+ "internal": {
390
+ "indexes": {}
391
+ }
392
+ }
@@ -29,6 +29,13 @@
29
29
  "when": 1765198112079,
30
30
  "tag": "0003_catalog_versions_and_revisions_relations",
31
31
  "breakpoints": true
32
+ },
33
+ {
34
+ "idx": 4,
35
+ "version": "6",
36
+ "when": 1734624000000,
37
+ "tag": "0004_normalize_relation_types",
38
+ "breakpoints": true
32
39
  }
33
40
  ]
34
41
  }
@@ -9,9 +9,21 @@ DROP INDEX IF EXISTS `idx_entities_key_source_created_at`;--> statement-breakpoi
9
9
  DROP INDEX IF EXISTS `idx_entities_key_source_is_current`;--> statement-breakpoint
10
10
  DROP INDEX IF EXISTS `idx_entities_key_source_is_default`;--> statement-breakpoint
11
11
  DROP INDEX IF EXISTS `idx_entities_key_source`;--> statement-breakpoint
12
+ -- Update all NULL values to '' first before creating unique index
12
13
  UPDATE `entities_relations` SET "source_version" = '' WHERE "source_version" IS NULL;--> statement-breakpoint
14
+ UPDATE `entities_relations` SET "source_revision" = '' WHERE "source_revision" IS NULL;--> statement-breakpoint
15
+ UPDATE `entities_relations` SET "target_version" = '' WHERE "target_version" IS NULL;--> statement-breakpoint
16
+ UPDATE `entities_relations` SET "target_revision" = '' WHERE "target_revision" IS NULL;--> statement-breakpoint
17
+ -- Delete duplicate relations keeping only the most recent one (by id)
18
+ DELETE FROM `entities_relations` WHERE `id` NOT IN (
19
+ SELECT MAX(`id`) FROM `entities_relations`
20
+ GROUP BY `source_key`, `target_key`, `source_version`, `target_version`, `source_revision`, `target_revision`
21
+ );--> statement-breakpoint
13
22
  -- We need to set default value to '', because NULL is not unique in sqlite
14
23
  ALTER TABLE `entities_relations` ALTER COLUMN "source_version" TO "source_version" text NOT NULL DEFAULT '';--> statement-breakpoint
24
+ ALTER TABLE `entities_relations` ALTER COLUMN "source_revision" TO "source_revision" text NOT NULL DEFAULT '';--> statement-breakpoint
25
+ ALTER TABLE `entities_relations` ALTER COLUMN "target_version" TO "target_version" text NOT NULL DEFAULT '';--> statement-breakpoint
26
+ ALTER TABLE `entities_relations` ALTER COLUMN "target_revision" TO "target_revision" text NOT NULL DEFAULT '';--> statement-breakpoint
15
27
  ALTER TABLE `entities_relations` ADD `is_deleted` integer DEFAULT false;--> statement-breakpoint
16
28
  CREATE INDEX `idx_entities_relations_source_key` ON `entities_relations` (`source_key`,`is_deleted`);--> statement-breakpoint
17
29
  CREATE INDEX `idx_entities_relations_target_key` ON `entities_relations` (`target_key`,`is_deleted`);--> statement-breakpoint
@@ -25,12 +37,6 @@ ALTER TABLE `entities` ADD `is_deleted` integer DEFAULT false;--> statement-brea
25
37
  CREATE INDEX `idx_entities_key_source_is_current` ON `entities` (`key`,`is_current`,`is_deleted`);--> statement-breakpoint
26
38
  CREATE INDEX `idx_entities_key_source_is_default` ON `entities` (`key`,`is_default_version`);--> statement-breakpoint
27
39
  CREATE UNIQUE INDEX `idx_entities_key_source` ON `entities` (`key`,`source`,`revision`,`version`);--> statement-breakpoint
28
- UPDATE `entities_relations` SET "source_revision" = '' WHERE "source_revision" IS NULL;--> statement-breakpoint
29
- ALTER TABLE `entities_relations` ALTER COLUMN "source_revision" TO "source_revision" text NOT NULL DEFAULT '';--> statement-breakpoint
30
- UPDATE `entities_relations` SET "target_version" = '' WHERE "target_version" IS NULL;--> statement-breakpoint
31
- ALTER TABLE `entities_relations` ALTER COLUMN "target_version" TO "target_version" text NOT NULL DEFAULT '';--> statement-breakpoint
32
- UPDATE `entities_relations` SET "target_revision" = '' WHERE "target_revision" IS NULL;--> statement-breakpoint
33
- ALTER TABLE `entities_relations` ALTER COLUMN "target_revision" TO "target_revision" text NOT NULL DEFAULT '';--> statement-breakpoint
34
40
  ALTER TABLE `entities_relations` DROP COLUMN `source_id`;--> statement-breakpoint
35
41
  ALTER TABLE `entities_relations` DROP COLUMN `target_id`;--> statement-breakpoint
36
42
  DROP INDEX IF EXISTS `idx_entities_key_source_is_current`;--> statement-breakpoint
@@ -7,6 +7,7 @@ export declare function applyFilter<T extends SQLiteSelect | SQLiteDelete>(sqlBu
7
7
  };
8
8
  export declare function convertFilterToWhereCondition(filter?: Filter): SQL | undefined;
9
9
  export declare function getFirstFilterFieldValue(filter: Filter | undefined, fieldName: string): FilterClause['value'] | undefined;
10
+ export declare function getAllFilterFieldValues(filter: Filter | undefined, fieldName: string): string[];
10
11
  export declare function parseFilterQuery(query?: string, availableFields?: string[], fieldsTransformations?: Record<string, string>): Filter | undefined;
11
12
  export declare function excludeFieldsFromFilter(filter: Filter | undefined, fieldsToExclude: string[]): Filter | undefined;
12
13
  //# sourceMappingURL=filter.d.ts.map
@@ -1 +1 @@
1
- import{and as O,between as R,eq as T,inArray as C,isNotNull as L,isNull as I,like as v,ne as k,notBetween as y,notInArray as W,notLike as b,or as d,sql as a}from"drizzle-orm";import{isFilterCondition as F}from"./types.js";import{transformToSnakeCase as q}from"./utils/transform-to-snake-case.js";import{isFieldAllowed as D}from"./utils/field-pattern-matcher.js";import{OPERATORS as h}from"./constants.js";const U=["domains","owners"],P=["tags"];function z(t,e){const o=J(e);return o?{sqlBuilder:t,whereCondition:o}:{sqlBuilder:t,whereCondition:null}}function J(t){if(t)return F(t)?j(t):x(t)}const j=t=>{const{op:e,conditions:o}=t,n=[];for(const l of o){if(F(l)){const r=j(l);r&&n.push(r);continue}const i=x(l);i&&n.push(i)}return e===h.AND?O(...n):d(...n)},H=(t,e)=>e.length>1?`$.${e.slice(1).join(".")}.${t}`:`$.${t}`,m=({operator:t,value:e,field:o,parentFields:n,negation:l})=>{const i=a.identifier(n[0]),r=H(o,n);switch(t){case"equal":return l?a`(json_extract(${i}, ${r}) != ${e} OR json_extract(${i}, ${r}) IS NULL)`:a`json_extract(${i}, ${r}) == ${e}`;case"equalNull":return l?a`json_extract(${i}, ${r}) IS NOT NULL`:a`json_extract(${i}, ${r}) IS NULL`;case"contains":return l?a`(json_extract(${i}, ${r}) NOT LIKE ${e} OR json_extract(${i}, ${r}) IS NULL)`:a`json_extract(${i}, ${r}) LIKE ${e}`;case"in":if(Array.isArray(e)){const s=e.map(c=>a`json_extract(${i}, ${r}) == ${c}`);return l?a`(NOT (${d(...s)}) OR json_extract(${i}, ${r}) IS NULL)`:d(...s)}break;case"between":if(Array.isArray(e)&&e.length===2)return l?a`(NOT (json_extract(${i}, ${r}) BETWEEN ${e[0]} AND ${e[1]}) OR json_extract(${i}, ${r}) IS NULL)`:a`json_extract(${i}, ${r}) BETWEEN ${e[0]} AND ${e[1]}`;break;default:throw new Error(`Unsupported operator: ${t} for json path`)}};function G(t,e){if(!t)return;const o=l=>{if(F(l)){for(const i of l.conditions){const r=o(i);if(r!==void 0)return r}return}if(l.field===e)return l.value},n=o(t);return typeof n=="string"?n.trim()===""?null:n.trim():n??null}const M=t=>{const{field:e,operator:o,value:n,modifier:l,parentFields:i}=t,r=l==="not";if(!i||i.length<1)throw new Error("convertNestedFilterClauseToSql called without parentFields");switch(o){case"equal":return m(n===null?{operator:"equalNull",value:n,field:e,parentFields:i,negation:r}:{operator:o,value:n,field:e,parentFields:i,negation:r});case"contains":if(typeof n=="string"){const s=n.startsWith("%")||n.endsWith("%")?n:`%${n}%`;return m({operator:o,value:s,field:e,parentFields:i,negation:r})}break;case"in":if(Array.isArray(n))return m({operator:o,value:n,field:e,parentFields:i,negation:r});break;case"between":if(Array.isArray(n)&&n.length===2)return m({operator:o,value:n,field:e,parentFields:i,negation:r});break;default:throw new Error(`Unsupported filter operator: ${o}`)}},x=t=>{const{field:e,operator:o,value:n,modifier:l,parentFields:i}=t;if(i&&i.length>=1)return M(t);const r=l==="not",s=a.identifier(e),c=P.includes(e),f=U.includes(e);switch(o){case"equal":return n===null?r?L(s):I(s):f?r?a`NOT EXISTS (SELECT 1 FROM json_each(${s}) WHERE json_extract(json_each.value, '$.key') = ${n})`:a`EXISTS (SELECT 1 FROM json_each(${s}) WHERE json_extract(json_each.value, '$.key') = ${n})`:c?r?a`NOT EXISTS (SELECT 1 FROM json_each(${s}) WHERE json_each.value = ${n})`:a`EXISTS (SELECT 1 FROM json_each(${s}) WHERE json_each.value = ${n})`:r?k(s,n):T(s,n);case"contains":if(typeof n=="string"){const u=n.startsWith("%")||n.endsWith("%")?n:`%${n}%`;return r?b(s,u):v(s,u)}break;case"in":if(Array.isArray(n)){if(f){const u=n.map(p=>a`EXISTS (SELECT 1 FROM json_each(${s}) WHERE json_extract(json_each.value, '$.key') = ${p})`);return r?a`NOT (${d(...u)})`:d(...u)}else if(c){const u=n.map(p=>a`EXISTS (SELECT 1 FROM json_each(${s}) WHERE json_each.value = ${p})`);return r?a`NOT (${d(...u)})`:d(...u)}return r?W(s,n):C(s,n)}break;case"between":if(Array.isArray(n)&&n.length===2)return r?y(s,n[0],n[1]):R(s,n[0],n[1]);break;default:throw new Error(`Unsupported filter operator: ${o}`)}},A=["'",'"'];function Z(t="",e=[],o={}){if(!t||!t.trim())return;const n=g(t);return w(n,e,o)}function S(t){const e=X(t);if(e.operator===":"){const o=N(e.value,",");if(o.length>1)return{operator:"in",field:e.field,parentFields:e.parentFields,value:o.map(E),modifier:e.modifier};const n=N(e.value,"..");return n.length===2?{operator:"between",field:e.field,parentFields:e.parentFields,value:[E(n[0]),E(n[1])],modifier:e.modifier}:{operator:"equal",field:e.field,parentFields:e.parentFields,value:e.value==="null"?null:E(e.value),modifier:e.modifier}}else if(e.operator==="~")return{operator:"contains",field:e.field,parentFields:e.parentFields,value:E(e.value),modifier:e.modifier};throw new Error(`Unsupported filter clause: ${t}`)}function X(t){const e="^(?<modifier>^-?)",o="(?<field>[a-z][\\w.]*)",n="(?<operator>:|~)",l="(?<value>.+)",i=new RegExp(`^${e}${o}${n}${l}$`,"i"),r=t.match(i);if(!r||!r.groups)throw new Error(`Invalid filter clause: ${t}`);const{operator:s,value:c,modifier:f}=r.groups,u=r.groups.field.split(".");return{field:u.pop(),parentFields:u,operator:s,value:c,modifier:f==="-"?"not":void 0}}function N(t,e){const o=[];let n="",l=!1,i=0;for(let r=0;r<t.length;r++){const s=t[r-1],c=t[r];if(i>0){i--;continue}s!=="\\"&&A.includes(c)&&(l=!l),!l&&t.slice(r,r+e.length)===e?(o.push(n),n="",i=e.length-1):n+=c}return n&&o.push(n),o}function E(t){for(const e of A)if(t.startsWith(e)&&t.endsWith(e))return t.slice(1,-1);return t}function g(t){let e="",o=0,n=!1,l="";const i=[];for(let s=0;s<t.length;s++){const c=t[s],f=t[s+1];if(['"',"'"].includes(c)&&(s===0||t[s-1]!=="\\")){if(!n){n=!0,l=c,e+=c;continue}if(c===l){n=!1,l="",e+=c;continue}}if(n){e+=c;continue}if(o===0){const u=f==="A"&&t.slice(s+1,s+5)===`${h.AND} `;if(c===" "&&u){const $=e.trim();$&&(i.push(S($)),e="");const _=g(t.slice(s+5));return{op:h.AND,conditions:[...i,_]}}const p=f==="O"&&t.slice(s+1,s+4)===`${h.OR} `;if(c===" "&&p){const $=e.trim();$&&(i.push(S($)),e="");const _=g(t.slice(s+4));return{op:h.OR,conditions:[...i,_]}}}if(c==="("){const u=e.trim();o===0&&u&&(i.push(S(u)),e=""),o++,e+=c;continue}if(c===")"){if(o--,e+=c,o===0){const u=e.slice(1,-1);i.push(g(u)),e=""}continue}e+=c}const r=e.trim();return r&&i.push(S(r)),i.length===1?i[0]:{op:h.AND,conditions:i}}function w(t,e,o){if("field"in t){const n=t.parentFields?.length?`${t.parentFields.join(".")}.${t.field}`:t.field;if(!D(n,e))throw new Error(`Invalid filter field: ${n}`);const l=t.parentFields?.length?t.field:o[t.field]||q(t.field);return{...t,field:l}}else return{...t,conditions:t.conditions.map(n=>w(n,e,o))}}function ee(t,e){if(!t)return;const o=i=>e.includes(i),n=i=>{if(F(i)){const r=i.conditions.map(n).filter(s=>s!==null);return r.length===0?null:r.length===1?r[0]:{...i,conditions:r}}else return o(i.field)?null:i};return n(t)||void 0}export{z as applyFilter,J as convertFilterToWhereCondition,ee as excludeFieldsFromFilter,G as getFirstFilterFieldValue,Z as parseFilterQuery};
1
+ import{and as O,between as R,eq as T,inArray as C,isNotNull as v,isNull as L,like as I,ne as y,notBetween as k,notInArray as W,notLike as b,or as d,sql as u}from"drizzle-orm";import{isFilterCondition as m}from"./types.js";import{transformToSnakeCase as q}from"./utils/transform-to-snake-case.js";import{isFieldAllowed as D}from"./utils/field-pattern-matcher.js";import{OPERATORS as h}from"./constants.js";const U=["domains","owners"],P=["tags"];function z(t,e){const o=J(e);return o?{sqlBuilder:t,whereCondition:o}:{sqlBuilder:t,whereCondition:null}}function J(t){if(t)return m(t)?A(t):j(t)}const A=t=>{const{op:e,conditions:o}=t,n=[];for(const s of o){if(m(s)){const i=A(s);i&&n.push(i);continue}const r=j(s);r&&n.push(r)}return e===h.AND?O(...n):d(...n)},H=(t,e)=>e.length>1?`$.${e.slice(1).join(".")}.${t}`:`$.${t}`,E=({operator:t,value:e,field:o,parentFields:n,negation:s})=>{const r=u.identifier(n[0]),i=H(o,n);switch(t){case"equal":return s?u`(json_extract(${r}, ${i}) != ${e} OR json_extract(${r}, ${i}) IS NULL)`:u`json_extract(${r}, ${i}) == ${e}`;case"equalNull":return s?u`json_extract(${r}, ${i}) IS NOT NULL`:u`json_extract(${r}, ${i}) IS NULL`;case"contains":return s?u`(json_extract(${r}, ${i}) NOT LIKE ${e} OR json_extract(${r}, ${i}) IS NULL)`:u`json_extract(${r}, ${i}) LIKE ${e}`;case"in":if(Array.isArray(e)){const l=e.map(c=>u`json_extract(${r}, ${i}) == ${c}`);return s?u`(NOT (${d(...l)}) OR json_extract(${r}, ${i}) IS NULL)`:d(...l)}break;case"between":if(Array.isArray(e)&&e.length===2)return s?u`(NOT (json_extract(${r}, ${i}) BETWEEN ${e[0]} AND ${e[1]}) OR json_extract(${r}, ${i}) IS NULL)`:u`json_extract(${r}, ${i}) BETWEEN ${e[0]} AND ${e[1]}`;break;default:throw new Error(`Unsupported operator: ${t} for json path`)}};function G(t,e){if(!t)return;const o=s=>{if(m(s)){for(const r of s.conditions){const i=o(r);if(i!==void 0)return i}return}if(s.field===e)return s.value},n=o(t);return typeof n=="string"?n.trim()===""?null:n.trim():n??null}function Z(t,e){if(!t)return[];const o=[],n=s=>{if(m(s)){for(const r of s.conditions)n(r);return}if(s.field===e){if(Array.isArray(s.value))o.push(...s.value.map(r=>String(r).trim()).filter(r=>r!==""));else if(s.value!==null&&s.value!==void 0){const r=String(s.value).trim();r!==""&&o.push(r)}}};return n(t),o}const M=t=>{const{field:e,operator:o,value:n,modifier:s,parentFields:r}=t,i=s==="not";if(!r||r.length<1)throw new Error("convertNestedFilterClauseToSql called without parentFields");switch(o){case"equal":return E(n===null?{operator:"equalNull",value:n,field:e,parentFields:r,negation:i}:{operator:o,value:n,field:e,parentFields:r,negation:i});case"contains":if(typeof n=="string"){const l=n.startsWith("%")||n.endsWith("%")?n:`%${n}%`;return E({operator:o,value:l,field:e,parentFields:r,negation:i})}break;case"in":if(Array.isArray(n))return E({operator:o,value:n,field:e,parentFields:r,negation:i});break;case"between":if(Array.isArray(n)&&n.length===2)return E({operator:o,value:n,field:e,parentFields:r,negation:i});break;default:throw new Error(`Unsupported filter operator: ${o}`)}},j=t=>{const{field:e,operator:o,value:n,modifier:s,parentFields:r}=t;if(r&&r.length>=1)return M(t);const i=s==="not",l=u.identifier(e),c=P.includes(e),f=U.includes(e);switch(o){case"equal":return n===null?i?v(l):L(l):f?i?u`NOT EXISTS (SELECT 1 FROM json_each(${l}) WHERE json_extract(json_each.value, '$.key') = ${n})`:u`EXISTS (SELECT 1 FROM json_each(${l}) WHERE json_extract(json_each.value, '$.key') = ${n})`:c?i?u`NOT EXISTS (SELECT 1 FROM json_each(${l}) WHERE json_each.value = ${n})`:u`EXISTS (SELECT 1 FROM json_each(${l}) WHERE json_each.value = ${n})`:i?y(l,n):T(l,n);case"contains":if(typeof n=="string"){const a=n.startsWith("%")||n.endsWith("%")?n:`%${n}%`;return i?b(l,a):I(l,a)}break;case"in":if(Array.isArray(n)){if(f){const a=n.map(p=>u`EXISTS (SELECT 1 FROM json_each(${l}) WHERE json_extract(json_each.value, '$.key') = ${p})`);return i?u`NOT (${d(...a)})`:d(...a)}else if(c){const a=n.map(p=>u`EXISTS (SELECT 1 FROM json_each(${l}) WHERE json_each.value = ${p})`);return i?u`NOT (${d(...a)})`:d(...a)}return i?W(l,n):C(l,n)}break;case"between":if(Array.isArray(n)&&n.length===2)return i?k(l,n[0],n[1]):R(l,n[0],n[1]);break;default:throw new Error(`Unsupported filter operator: ${o}`)}},x=["'",'"'];function ee(t="",e=[],o={}){if(!t||!t.trim())return;const n=g(t);return w(n,e,o)}function S(t){const e=X(t);if(e.operator===":"){const o=N(e.value,",");if(o.length>1)return{operator:"in",field:e.field,parentFields:e.parentFields,value:o.map(F),modifier:e.modifier};const n=N(e.value,"..");return n.length===2?{operator:"between",field:e.field,parentFields:e.parentFields,value:[F(n[0]),F(n[1])],modifier:e.modifier}:{operator:"equal",field:e.field,parentFields:e.parentFields,value:e.value==="null"?null:F(e.value),modifier:e.modifier}}else if(e.operator==="~")return{operator:"contains",field:e.field,parentFields:e.parentFields,value:F(e.value),modifier:e.modifier};throw new Error(`Unsupported filter clause: ${t}`)}function X(t){const e="^(?<modifier>^-?)",o="(?<field>[a-z][\\w.]*)",n="(?<operator>:|~)",s="(?<value>.+)",r=new RegExp(`^${e}${o}${n}${s}$`,"i"),i=t.match(r);if(!i||!i.groups)throw new Error(`Invalid filter clause: ${t}`);const{operator:l,value:c,modifier:f}=i.groups,a=i.groups.field.split(".");return{field:a.pop(),parentFields:a,operator:l,value:c,modifier:f==="-"?"not":void 0}}function N(t,e){const o=[];let n="",s=!1,r=0;for(let i=0;i<t.length;i++){const l=t[i-1],c=t[i];if(r>0){r--;continue}l!=="\\"&&x.includes(c)&&(s=!s),!s&&t.slice(i,i+e.length)===e?(o.push(n),n="",r=e.length-1):n+=c}return n&&o.push(n),o}function F(t){for(const e of x)if(t.startsWith(e)&&t.endsWith(e))return t.slice(1,-1);return t}function g(t){let e="",o=0,n=!1,s="";const r=[];for(let l=0;l<t.length;l++){const c=t[l],f=t[l+1];if(['"',"'"].includes(c)&&(l===0||t[l-1]!=="\\")){if(!n){n=!0,s=c,e+=c;continue}if(c===s){n=!1,s="",e+=c;continue}}if(n){e+=c;continue}if(o===0){const a=f==="A"&&t.slice(l+1,l+5)===`${h.AND} `;if(c===" "&&a){const $=e.trim();$&&(r.push(S($)),e="");const _=g(t.slice(l+5));return{op:h.AND,conditions:[...r,_]}}const p=f==="O"&&t.slice(l+1,l+4)===`${h.OR} `;if(c===" "&&p){const $=e.trim();$&&(r.push(S($)),e="");const _=g(t.slice(l+4));return{op:h.OR,conditions:[...r,_]}}}if(c==="("){const a=e.trim();o===0&&a&&(r.push(S(a)),e=""),o++,e+=c;continue}if(c===")"){if(o--,e+=c,o===0){const a=e.slice(1,-1);r.push(g(a)),e=""}continue}e+=c}const i=e.trim();return i&&r.push(S(i)),r.length===1?r[0]:{op:h.AND,conditions:r}}function w(t,e,o){if("field"in t){const n=t.parentFields?.length?`${t.parentFields.join(".")}.${t.field}`:t.field;if(!D(n,e))throw new Error(`Invalid filter field: ${n}`);const s=t.parentFields?.length?t.field:o[t.field]||q(t.field);return{...t,field:s}}else return{...t,conditions:t.conditions.map(n=>w(n,e,o))}}function ne(t,e){if(!t)return;const o=r=>e.includes(r),n=r=>{if(m(r)){const i=r.conditions.map(n).filter(l=>l!==null);return i.length===0?null:i.length===1?i[0]:{...r,conditions:i}}else return o(r.field)?null:r};return n(t)||void 0}export{z as applyFilter,J as convertFilterToWhereCondition,ne as excludeFieldsFromFilter,Z as getAllFilterFieldValues,G as getFirstFilterFieldValue,ee as parseFilterQuery};
@@ -1,4 +1,4 @@
1
- import"../node-crypto-polyfill.js";import{DOMParser as U}from"@xmldom/xmldom";import{SignedXml as B}from"xml-crypto";import F from"xpath";import{deflateSync as J,inflateSync as q}from"fflate";import{createHash as H}from"crypto";import{ulid as W}from"ulid";import{AuthProviderType as d,DEFAULT_TEAM_CLAIM_NAME as K}from"@redocly/config";import{AUTH_URL as Q,JWT_SECRET_KEY as _}from"../constants/common.js";import{getPathPrefix as X,withPathPrefix as Y}from"@redocly/theme/core/utils";import{DEFAULT_AUTHENTICATED_TEAM as G,REQUIRED_OIDC_SCOPES as D,ServerRoutes as P}from"../../constants/common.js";import{appendQueryParams as Z}from"../../utils/url/append-query-params.js";import{logger as ee}from"../tools/notifiers/logger.js";import{randomString as te}from"../utils/crypto/random-string.js";import{randomUUID as R}from"../utils/crypto/random-uuid.js";import{AlgorithmTypes as I,JwtTokenExpired as ne}from"./jwt/types.js";import*as p from"./jwt/jwt.js";import{parseTeamClaimToArray as re}from"../utils/index.js";import{arrayBufferToBase64 as oe,decodeBase64 as j,encodeBase64URL as ae,urlSafeBase64 as v}from"./jwt/encode.js";import{formatSamlCertificate as se}from"./utils/format-saml-certificate.js";function E(e){return e?.type===d.OIDC}function ie(e){return e?.type===d.SAML2}async function ze(e,t){if(E(t))return ce(e,t);if(ie(t))return ue(e,t)}async function ce(e,t){const n=await V(e,t),r=new Set((t.scopes||[]).concat(D)),o=t.authorizationRequestCustomParams||{};return{type:d.OIDC,idpId:e,name:"OAuth provider",authorizationEndpoint:n.authorization_endpoint,clientId:t.clientId,responseType:"code",scope:Array.from(r).join(" "),extraParams:o,pkce:t.pkce}}function ue(e,t){return{type:d.SAML2,idpId:e,name:"SAML2 provider",ssoUrl:t.ssoUrl,issuerId:t.issuerId,entityId:t.entityId||t.issuerId}}async function Be(e,t,n,r,o={}){const a=new Set((r.scopes||[]).concat(D));return await fetch(e,{method:"POST",body:new URLSearchParams({client_id:r.clientId,scope:Array.from(a).join(" "),code:t,redirect_uri:N(n),grant_type:"authorization_code",...r.clientSecret?{client_secret:r.clientSecret}:{},...o}).toString(),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"}}).then(s=>s.json())}function de(e,{authorizationEndpoint:t,clientId:n,responseType:r,scope:o,extraParams:a,idpId:s,pkce:i},l,A,w){if(!t||!n||!r||!o)return{loginUrl:void 0};const u=new URL(t),f=w?.redirectUriOverride??`${e}${Y(P.OIDC_CALLBACK)}`,S={state:R(),idpId:s,redirectUri:f,redirectTo:l,branch:w?.branchOverride??me(e),inviteCode:A,source:w?.sourceOverride??"portal"},h={};if(i){const m=v(te(50)),g=v(H("sha256").update(m).digest("base64")),x="S256";u.searchParams.append("code_challenge",g),u.searchParams.append("code_challenge_method",x),h.code_verifier={value:m,options:{secure:!0,httpOnly:!0,expires:new Date(Date.now()+1e3*60*10),path:X()||"/"}}}u.searchParams.append("client_id",n),u.searchParams.append("scope",o),u.searchParams.append("response_type",r),u.searchParams.append("redirect_uri",N(f)),u.searchParams.append("state",ae(JSON.stringify(S)));for(const m in a)a[m]!==void 0&&u.searchParams.append(m,a[m]);return{loginUrl:u.toString(),cookies:h}}function Fe(e,t,n,r){const o=new URL(e);return o.searchParams.append("post_logout_redirect_uri",t),r&&o.searchParams.append("state",r),o.searchParams.append("id_token_hint",n),o.toString()}async function Je(e){const t=Math.floor(Date.now()/1e3),n=t+(e.ttlSec??600);return p.sign({type:"mcp_auth_code",client_id:e.clientId,redirect_uri:e.redirectUri,id_token:e.idToken,iat:t,exp:n},_)}async function qe(e){const{header:t,payload:n}=p.decode(e),o=Object.values(I).includes(t.alg)?t.alg:I.HS256;if(await p.verify(e,_,o),!n||typeof n!="object")throw new Error("Malformed authorization code");const a=n;if((a.typ??a.type)!=="mcp_auth_code")throw new Error("Invalid authorization code type");const i=n;if(!i.client_id||!i.redirect_uri)throw new Error("Authorization code missing required claims");if(i.exp&&Date.now()>=i.exp*1e3)throw new Error("Authorization code expired");return i}function He(e){const t=e||W(),n=t.startsWith("mcp_")?t:`mcp_${t}`;return{id:n,object:"mcp_session",uri:`urn:redocly:realm:mcp:session:${n}`}}function N(e){return e.match(/^https:\/\/preview-[^\.]+--/)?"https://previewauth--"+e.split("--")[1]:e.match(/^(https:\/\/[^\.]+)--[^\.]+\.preview\./)?e.replace(/^(https:\/\/[^\.]+?)--[^\.]+\.preview\./,"$1.previewauth."):e}function me(e){return e.match(/^(https:\/\/[^\.]+)--([^\.]+)\.preview\./)?.[2]||void 0}function le(e){return e.type===d.OIDC}function pe(e){return e.type===d.SAML2}function We(e,t,n,r){return le(e)?de(t,e,n,r):pe(e)?fe(t,e,n,r):{}}function fe(e,t,n,r){const a=`<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
1
+ import"../node-crypto-polyfill.js";import{DOMParser as U}from"@xmldom/xmldom";import{SignedXml as B}from"xml-crypto";import F from"xpath";import{deflateSync as J,inflateSync as q}from"fflate";import{createHash as H}from"crypto";import{ulid as W}from"ulid";import{AuthProviderType as u,DEFAULT_TEAM_CLAIM_NAME as K}from"@redocly/config";import{AUTH_URL as Q,JWT_SECRET_KEY as _}from"../constants/common.js";import{getPathPrefix as X,withPathPrefix as Y}from"@redocly/theme/core/utils";import{DEFAULT_AUTHENTICATED_TEAM as G,REQUIRED_OIDC_SCOPES as D,ServerRoutes as P}from"../../constants/common.js";import{appendQueryParams as Z}from"../../utils/url/append-query-params.js";import{logger as ee}from"../tools/notifiers/logger.js";import{randomString as te}from"../utils/crypto/random-string.js";import{randomUUID as R}from"../utils/crypto/random-uuid.js";import{AlgorithmTypes as I,JwtTokenExpired as ne}from"./jwt/types.js";import*as p from"./jwt/jwt.js";import{parseTeamClaimToArray as re}from"../utils/index.js";import{arrayBufferToBase64 as ae,decodeBase64 as v,encodeBase64URL as oe,urlSafeBase64 as j}from"./jwt/encode.js";import{formatSamlCertificate as se}from"./utils/format-saml-certificate.js";function N(e){return e?.type===u.OIDC}function ie(e){return e?.type===u.SAML2}async function ze(e,t){if(N(t))return ce(e,t);if(ie(t))return ue(e,t)}async function ce(e,t){const n=await V(e,t),r=new Set((t.scopes||[]).concat(D)),a=t.authorizationRequestCustomParams||{};return{type:u.OIDC,idpId:e,name:"OAuth provider",authorizationEndpoint:n.authorization_endpoint,clientId:t.clientId,responseType:"code",scope:Array.from(r).join(" "),extraParams:a,pkce:t.pkce}}function ue(e,t){return{type:u.SAML2,idpId:e,name:"SAML2 provider",ssoUrl:t.ssoUrl,issuerId:t.issuerId,entityId:t.entityId||t.issuerId}}async function Be(e,t,n,r,a={}){const o=new Set((r.scopes||[]).concat(D));return await fetch(e,{method:"POST",body:new URLSearchParams({client_id:r.clientId,scope:Array.from(o).join(" "),code:t,redirect_uri:E(n),grant_type:"authorization_code",...r.clientSecret?{client_secret:r.clientSecret}:{},...a}).toString(),headers:{"Content-Type":"application/x-www-form-urlencoded",Accept:"application/json"}}).then(s=>s.json())}function de(e,{authorizationEndpoint:t,clientId:n,responseType:r,scope:a,extraParams:o,idpId:s,pkce:l},m,A,w){if(!t||!n||!r||!a)return{loginUrl:void 0};const c=new URL(t),f=w?.redirectUriOverride??`${e}${Y(P.OIDC_CALLBACK)}`,S={state:R(),idpId:s,redirectUri:f,redirectTo:m,branch:w?.branchOverride??me(e),inviteCode:A,source:w?.sourceOverride??"portal"},h={};if(l){const d=j(te(50)),g=j(H("sha256").update(d).digest("base64")),x="S256";c.searchParams.append("code_challenge",g),c.searchParams.append("code_challenge_method",x),h.code_verifier={value:d,options:{secure:!0,httpOnly:!0,expires:new Date(Date.now()+1e3*60*10),path:X()||"/"}}}c.searchParams.append("client_id",n),c.searchParams.append("scope",a),c.searchParams.append("response_type",r),c.searchParams.append("redirect_uri",E(f)),c.searchParams.append("state",oe(JSON.stringify(S)));for(const d in o)o[d]!==void 0&&c.searchParams.append(d,o[d]);return{loginUrl:c.toString(),cookies:h}}function Fe(e,t,n,r){const a=new URL(e);return a.searchParams.append("post_logout_redirect_uri",t),r&&a.searchParams.append("state",r),a.searchParams.append("id_token_hint",n),a.toString()}async function Je(e){const t=Math.floor(Date.now()/1e3),n=t+(e.ttlSec??600);return p.sign({type:"mcp_auth_code",client_id:e.clientId,redirect_uri:e.redirectUri,id_token:e.idToken,iat:t,exp:n},_)}async function qe(e){const{header:t,payload:n}=p.decode(e),a=Object.values(I).includes(t.alg)?t.alg:I.HS256;if(await p.verify(e,_,a),n.type!=="mcp_auth_code")throw new Error("Invalid authorization code type");if(!n.client_id||!n.redirect_uri)throw new Error("Authorization code missing required claims");if(typeof n.exp=="number"&&Date.now()>=n.exp*1e3)throw new Error("Authorization code expired");return n}function He(e){const t=e||W(),n=t.startsWith("mcp_")?t:`mcp_${t}`;return{id:n,object:"mcp_session",uri:`urn:redocly:realm:mcp:session:${n}`}}function E(e){return e.match(/^https:\/\/preview-[^\.]+--/)?"https://previewauth--"+e.split("--")[1]:e.match(/^(https:\/\/[^\.]+)--[^\.]+\.preview\./)?e.replace(/^(https:\/\/[^\.]+?)--[^\.]+\.preview\./,"$1.previewauth."):e}function me(e){return e.match(/^(https:\/\/[^\.]+)--([^\.]+)\.preview\./)?.[2]||void 0}function le(e){return e.type===u.OIDC}function pe(e){return e.type===u.SAML2}function We(e,t,n,r){return le(e)?de(t,e,n,r):pe(e)?fe(t,e,n,r):{}}function fe(e,t,n,r){const o=`<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
2
2
  xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
3
3
  Version="2.0"
4
4
  ID="_${R()}"
@@ -9,4 +9,4 @@ import"../node-crypto-polyfill.js";import{DOMParser as U}from"@xmldom/xmldom";im
9
9
  <samlp:NameIDPolicy
10
10
  AllowCreate="true"
11
11
  Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"/>
12
- </samlp:AuthnRequest>`,s=he(a);return{loginUrl:Z(t.ssoUrl,{SAMLRequest:s,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal"})})}}function he(e){return oe(J(new TextEncoder().encode(e)).buffer)}function Ke(e){const t=j(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const n=q(new Uint8Array(atob(e).split("").map(r=>r.charCodeAt(0))));return new TextDecoder().decode(n)}function Qe(e){try{return JSON.parse(j(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function Xe(e){const t=new U().parseFromString(e,"application/xml"),r=c(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,a=c(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",s=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],i=s&&s.nodeValue||void 0,l=c(t,"//*[local-name(.)='Audience']/text()")[0],A=l&&l.nodeValue||void 0,u=c(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",f=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],S=f&&f.nodeValue||"",h=c(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],m=h&&h.nodeValue||"",g=c(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],x=ye(g),T={},k=c(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(k.length)for(const C of k){const O=c(C,"./@Name")[0];if(O.nodeValue){const b=c(C,"./*[local-name(.)='AttributeValue']/text()")[0];b?.nodeValue&&(T[O.nodeValue]=b.nodeValue)}}return{uid:S,success:r,expiresAt:x,issuerId:i,entityId:A,attrs:T,cert:u,nameFormat:m,destination:a}}function ye(e){const t=typeof e?.nodeValue=="string"&&L(Date.parse(e.nodeValue)),n=L(Date.now()),r=L(Date.now()+720*60*1e3);return t?t>n&&t<r?r:t:n}function L(e){return Math.floor(e/1e3)}const M={},y={jwks:{}};async function V(e,t){return M[e]||(M[e]=t.configurationUrl?await $(t.configurationUrl):t.configuration),M[e]}async function we(e){for(const t of Object.keys(e)){const n=e[t];if(!E(n))continue;const r=await V(t,n);if(r.jwks_uri){const o=await $(r.jwks_uri);for(const a of o.keys)y.jwks[a.kid]={...a,idpId:t}}}}async function $(e){return fetch(e,{headers:{Accept:"application/json"}}).then(t=>t.json())}async function Ye(e){return fetch(`${Q}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}function Ge(e){if(!e.configurationUrl)return!1;const t=new URL(e.configurationUrl);return["localhost","127.0.0.1","blueharvest.cloud","bhstage.cloud","cloud.redocly.com","beta.redocly.com","cloud.eu.redocly.com","beta.eu.redocly.com","cba.au.redocly.com"].some(r=>Ae(t.hostname,r))}function Ae(e,t){return e===t||e.endsWith(`.${t}`)}async function Ze(e,t){const n=new U().parseFromString(e),r=c(n,"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];if(!r)throw new Error("Cannot find Signature in the SAML response");const o=se(t),a=new B({publicCert:o});a.loadSignature(r);try{return a.checkSignature(e)}catch{return!1}}function et(e,t,n,r){t==="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"&&(e=n["http://schemas.microsoft.com/identity/claims/objectidentifier"]);let o;(t==="urn:oasis:names:tc:SAML:2.0:nameid-format:email"||t==="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")&&(o=e),t==="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"&&e?.match(/.+@.+/)&&(o=e);const a=n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],s=a?.match(/.+@.+/);return o=o||n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(s?a:void 0),o=o?.toLowerCase(),{sub:e,given_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"],family_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"],name:n["http://schemas.microsoft.com/identity/claims/displayname"]||a,email:o,email_verified:!0,teams:r?re(n[r]):[]}}function z(e,t={}){return e.map(n=>t[n]||n)}async function tt(e,t){if(!t)return{};const n=t.authorization;if(!n)return{};try{const r=p.decode(n);if(r.header.alg===I.RS256){y.jwks[r.header.kid]===void 0&&await we(e);const l=y.jwks[r.header.kid];if(!l)return y.jwks[r.header.kid]=null,{};await p.verify(n,l,r.header.alg)}else await p.verify(n,_,r.header.alg);const o=r.payload.idpId||y.jwks[r.header.kid]?.idpId,a=e[o]||{},s=xe(a),i=ge(a);return{...r.payload,email:r.payload.email?.toLowerCase(),idpId:o,teams:Array.from(new Set([...z(r.payload.teams||[],i),..."defaultTeams"in a&&a.defaultTeams||[],...z("teamsClaimName"in a&&r.payload[s||""]||[],i),G])),name:Se(r.payload),isAuthenticated:!0,idpAccessToken:t.idp_access_token,federatedAccessToken:t.federated_access_token,federatedIdToken:t.federated_id_token,authCookie:n}}catch(r){r instanceof ne||ee.error("Malformed JWT token: %s",r.message)}return{}}function Se(e){return e.name||e.given_name||e.email}function ge(e){switch(e.type){case d.SAML2:return e.teamsAttributeMap;case d.OIDC:return e.teamsClaimMap;default:return}}function xe(e){switch(e.type){case d.SAML2:return e.teamsAttributeName;case d.OIDC:return e.teamsClaimName;default:return K}}function c(e,t){return F.select(t,e)||[]}export{We as buildLoginUrl,de as buildOidcLoginUrl,Fe as buildOidcLogoutUrl,fe as buildSAML2LoginUrl,Je as createMcpAuthorizationCode,He as createMcpSessionResource,Ke as decodeSamlResponse,he as encodeSAML2,et as extractUserClaims,ze as getAuthProviderLoginParams,ce as getOidcLoginParams,V as getOidcMetadata,Ye as getRedoclyTokenPayload,ue as getSaml2LoginParams,tt as getUserParamsFromCookies,Se as getUsernameFromPayload,E as isOidcProviderConfig,Ge as isRedoclySso,ie as isSaml2ProviderConfig,Be as oidcExchangeCodeForToken,Qe as parseOidcState,me as parsePreviewBranch,Xe as parseSamlResponse,N as rewritePreviewAuthRedirectUri,qe as verifyMcpAuthorizationCode,Ze as verifySAMLResponse};
12
+ </samlp:AuthnRequest>`,s=he(o);return{loginUrl:Z(t.ssoUrl,{SAMLRequest:s,RelayState:JSON.stringify({idpId:t.idpId,redirectTo:n,inviteCode:r,source:"portal"})})}}function he(e){return ae(J(new TextEncoder().encode(e)).buffer)}function Ke(e){const t=v(e);if(t.startsWith("<samlp:Response")||t.indexOf("<saml2p:Response")>-1)return t;const n=q(new Uint8Array(atob(e).split("").map(r=>r.charCodeAt(0))));return new TextDecoder().decode(n)}function Qe(e){try{return JSON.parse(v(e||""))}catch{throw new Error("Invalid OAuth2 state")}}function Xe(e){const t=new U().parseFromString(e,"application/xml"),r=i(t,"//*[local-name(.)='StatusCode']/@Value")[0]?.nodeValue?.endsWith("Success")||!1,o=i(t,"//*[local-name(.)='Response']/@Destination")[0]?.nodeValue||"",s=i(t,"//*[local-name(.)='Assertion']//*[local-name(.)='Issuer']/text()")[0],l=s&&s.nodeValue||void 0,m=i(t,"//*[local-name(.)='Audience']/text()")[0],A=m&&m.nodeValue||void 0,c=i(t,"//*[local-name(.)='Assertion']//*[local-name(.)='X509Certificate']/text()")[0]?.nodeValue||"",f=i(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/text()")[0],S=f&&f.nodeValue||"",h=i(t,"//*[local-name(.)='Subject']//*[local-name(.)='NameID']/@Format")[0],d=h&&h.nodeValue||"",g=i(t,"//*[local-name(.)='Conditions']/@NotOnOrAfter")[0],x=ye(g),k={},T=i(t,"//*[local-name(.)='AttributeStatement']//*[local-name(.)='Attribute']");if(T.length)for(const C of T){const O=i(C,"./@Name")[0];if(O.nodeValue){const b=i(C,"./*[local-name(.)='AttributeValue']/text()")[0];b?.nodeValue&&(k[O.nodeValue]=b.nodeValue)}}return{uid:S,success:r,expiresAt:x,issuerId:l,entityId:A,attrs:k,cert:c,nameFormat:d,destination:o}}function ye(e){const t=typeof e?.nodeValue=="string"&&L(Date.parse(e.nodeValue)),n=L(Date.now()),r=L(Date.now()+720*60*1e3);return t?t>n&&t<r?r:t:n}function L(e){return Math.floor(e/1e3)}const M={},y={jwks:{}};async function V(e,t){return M[e]||(M[e]=t.configurationUrl?await $(t.configurationUrl):t.configuration),M[e]}async function we(e){for(const t of Object.keys(e)){const n=e[t];if(!N(n))continue;const r=await V(t,n);if(r.jwks_uri){const a=await $(r.jwks_uri);for(const o of a.keys)y.jwks[o.kid]={...o,idpId:t}}}}async function $(e){return fetch(e,{headers:{Accept:"application/json"}}).then(t=>t.json())}async function Ye(e){return fetch(`${Q}/oidc/userinfo`,{headers:{Accept:"application/json",Authorization:`Bearer ${e}`}}).then(t=>t.status===200?t.json():void 0).catch(()=>{})}function Ge(e){if(!e.configurationUrl)return!1;const t=new URL(e.configurationUrl);return["localhost","127.0.0.1","blueharvest.cloud","bhstage.cloud","cloud.redocly.com","beta.redocly.com","cloud.eu.redocly.com","beta.eu.redocly.com","cba.au.redocly.com"].some(r=>Ae(t.hostname,r))}function Ae(e,t){return e===t||e.endsWith(`.${t}`)}async function Ze(e,t){const n=new U().parseFromString(e),r=i(n,"//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];if(!r)throw new Error("Cannot find Signature in the SAML response");const a=se(t),o=new B({publicCert:a});o.loadSignature(r);try{return o.checkSignature(e)}catch{return!1}}function et(e,t,n,r){t==="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"&&(e=n["http://schemas.microsoft.com/identity/claims/objectidentifier"]);let a;(t==="urn:oasis:names:tc:SAML:2.0:nameid-format:email"||t==="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")&&(a=e),t==="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"&&e?.match(/.+@.+/)&&(a=e);const o=n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"],s=o?.match(/.+@.+/);return a=a||n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"]||(s?o:void 0),a=a?.toLowerCase(),{sub:e,given_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"],family_name:n["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"],name:n["http://schemas.microsoft.com/identity/claims/displayname"]||o,email:a,email_verified:!0,teams:r?re(n[r]):[]}}function z(e,t={}){return e.map(n=>t[n]||n)}async function tt(e,t){if(!t)return{};const n=t.authorization;if(!n)return{};try{const r=p.decode(n);if(r.header.alg===I.RS256){y.jwks[r.header.kid]===void 0&&await we(e);const m=y.jwks[r.header.kid];if(!m)return y.jwks[r.header.kid]=null,{};await p.verify(n,m,r.header.alg)}else await p.verify(n,_,r.header.alg);const a=r.payload.idpId||y.jwks[r.header.kid]?.idpId,o=e[a]||{},s=xe(o),l=ge(o);return{...r.payload,email:r.payload.email?.toLowerCase(),idpId:a,teams:Array.from(new Set([...z(r.payload.teams||[],l),..."defaultTeams"in o&&o.defaultTeams||[],...z("teamsClaimName"in o&&r.payload[s||""]||[],l),G])),name:Se(r.payload),isAuthenticated:!0,idpAccessToken:t.idp_access_token,federatedAccessToken:t.federated_access_token,federatedIdToken:t.federated_id_token,authCookie:n}}catch(r){r instanceof ne||ee.error("Malformed JWT token: %s",r.message)}return{}}function Se(e){return e.name||e.given_name||e.email}function ge(e){switch(e.type){case u.SAML2:return e.teamsAttributeMap;case u.OIDC:return e.teamsClaimMap;default:return}}function xe(e){switch(e.type){case u.SAML2:return e.teamsAttributeName;case u.OIDC:return e.teamsClaimName;default:return K}}function i(e,t){return F.select(t,e)||[]}export{We as buildLoginUrl,de as buildOidcLoginUrl,Fe as buildOidcLogoutUrl,fe as buildSAML2LoginUrl,Je as createMcpAuthorizationCode,He as createMcpSessionResource,Ke as decodeSamlResponse,he as encodeSAML2,et as extractUserClaims,ze as getAuthProviderLoginParams,ce as getOidcLoginParams,V as getOidcMetadata,Ye as getRedoclyTokenPayload,ue as getSaml2LoginParams,tt as getUserParamsFromCookies,Se as getUsernameFromPayload,N as isOidcProviderConfig,Ge as isRedoclySso,ie as isSaml2ProviderConfig,Be as oidcExchangeCodeForToken,Qe as parseOidcState,me as parsePreviewBranch,Xe as parseSamlResponse,E as rewritePreviewAuthRedirectUri,qe as verifyMcpAuthorizationCode,Ze as verifySAMLResponse};
@@ -4,6 +4,7 @@ export declare function authorizeHandler(ctx: Context): Promise<Response>;
4
4
  export declare function redoclyLoginCallbackHandler(): Handler;
5
5
  export declare function oidcCallbackHandler(store: Store): Handler;
6
6
  export declare function logoutHandler(store: Store): (ctx: Context) => Promise<Response>;
7
+ export declare function postLogoutHandler(store: Store): (ctx: Context) => Promise<Response>;
7
8
  export declare function inviteHandler(store: Store): (ctx: Context) => Promise<Response>;
8
9
  export declare function idpLoginHandler(store: Store): (ctx: Context) => Promise<Response>;
9
10
  export declare function samlCallbackHandler(store: Store): Handler;