@yrest/cli 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +158 -53
- package/assets/yrest-banner.png +0 -0
- package/assets/yrest-lockup.png +0 -0
- package/assets/yrest-lockup.svg +20 -0
- package/assets/yrest-logo.png +0 -0
- package/assets/yrest-monochrome.png +0 -0
- package/dist/cli/index.js +1273 -145
- package/dist/cli/index.mjs +1270 -142
- package/dist/index.d.mts +52 -10
- package/dist/index.d.ts +52 -10
- package/dist/index.js +1223 -94
- package/dist/index.mjs +1220 -91
- package/package.json +1 -1
- package/assets/logo-color.png +0 -0
- package/assets/logo-figure.png +0 -0
- package/assets/logo-text.png +0 -0
- package/assets/logo-white.png +0 -0
- package/assets/yRest-banner.png +0 -0
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<img src="assets/
|
|
2
|
+
<img src="assets/yrest-banner.png" alt="yRest" width="100%" />
|
|
3
3
|
</div>
|
|
4
4
|
|
|
5
5
|
<br/>
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
[](https://github.com/aggiovato/yRest/actions)
|
|
11
11
|
[](https://www.npmjs.com/package/@yrest/cli)
|
|
12
12
|
[](https://www.typescriptlang.org/)
|
|
13
|
-
[](https://socket.dev/npm/package/@yrest/cli)
|
|
14
14
|
|
|
15
15
|
YAML-powered json-server alternative. Zero-config REST API mock server with full CRUD, relations, filters and snapshots from a `db.yml` file.
|
|
16
16
|
|
|
@@ -48,30 +48,33 @@ DELETE /users/1 → 200 OK
|
|
|
48
48
|
|
|
49
49
|
A YAML-first alternative to json-server for frontend development.
|
|
50
50
|
|
|
51
|
-
| Feature
|
|
52
|
-
|
|
|
53
|
-
| YAML database
|
|
54
|
-
| Zero config
|
|
55
|
-
| Full CRUD
|
|
56
|
-
| Field operators (`_gte`, `_like`, `_regex`…)
|
|
57
|
-
| Full-text search
|
|
58
|
-
| Relations: many2one, one2one, many2many
|
|
59
|
-
| Nested routes + bidirectional many2many
|
|
60
|
-
| Auto-embedding (`nested: true`)
|
|
61
|
-
| Field projection (`_fields`)
|
|
62
|
-
| Pageable mode (envelope response)
|
|
63
|
-
| Custom static routes (`_routes`)
|
|
64
|
-
| Template variables in responses
|
|
65
|
-
| Handler functions (JS logic)
|
|
66
|
-
| Conditional scenarios (`scenarios:`)
|
|
67
|
-
| Snapshot endpoints
|
|
68
|
-
| Config file
|
|
69
|
-
| API overview page (`/_about`)
|
|
70
|
-
| Watch mode
|
|
71
|
-
| Readonly mode
|
|
72
|
-
| Atomic writes
|
|
73
|
-
| TypeScript types
|
|
74
|
-
| Programmatic API for test frameworks
|
|
51
|
+
| Feature | yrest | json-server |
|
|
52
|
+
| --------------------------------------------------- | :---: | :---------: |
|
|
53
|
+
| YAML database | ✅ | ❌ |
|
|
54
|
+
| Zero config | ✅ | ✅ |
|
|
55
|
+
| Full CRUD | ✅ | ✅ |
|
|
56
|
+
| Field operators (`_gte`, `_like`, `_regex`…) | ✅ | ⚠️ |
|
|
57
|
+
| Full-text search | ✅ | ✅ |
|
|
58
|
+
| Relations: many2one, one2one, many2many | ✅ | ⚠️ |
|
|
59
|
+
| Nested routes + bidirectional many2many | ✅ | ✅ |
|
|
60
|
+
| Auto-embedding (`nested: true`) | ✅ | ❌ |
|
|
61
|
+
| Field projection (`_fields`) | ✅ | ❌ |
|
|
62
|
+
| Pageable mode (envelope response) | ✅ | ❌ |
|
|
63
|
+
| Custom static routes (`_routes`) | ✅ | ❌ |
|
|
64
|
+
| Template variables in responses | ✅ | ❌ |
|
|
65
|
+
| Handler functions (JS logic) | ✅ | ❌ |
|
|
66
|
+
| Conditional scenarios (`scenarios:`) | ✅ | ❌ |
|
|
67
|
+
| Snapshot endpoints | ✅ | ❌ |
|
|
68
|
+
| Config file | ✅ | ⚠️ |
|
|
69
|
+
| API overview page (`/_about`) | ✅ | ❌ |
|
|
70
|
+
| Watch mode | ✅ | ✅ |
|
|
71
|
+
| Readonly mode | ✅ | ❌ |
|
|
72
|
+
| Atomic writes | ✅ | ✅ |
|
|
73
|
+
| TypeScript types | ✅ | ❌ |
|
|
74
|
+
| Programmatic API for test frameworks | ✅ | ❌ |
|
|
75
|
+
| OpenAPI 3.0 spec (`GET /_openapi`, `yrest openapi`) | ✅ | ❌ |
|
|
76
|
+
| Field annotations (`_schema`) | ✅ | ❌ |
|
|
77
|
+
| Compact relation DSL (`m2o:target@fk[card]+nested`) | ✅ | ❌ |
|
|
75
78
|
|
|
76
79
|
---
|
|
77
80
|
|
|
@@ -140,6 +143,31 @@ npx @yrest/cli init --sample relational --file api.yml
|
|
|
140
143
|
|
|
141
144
|
---
|
|
142
145
|
|
|
146
|
+
### `openapi`
|
|
147
|
+
|
|
148
|
+
Generates an OpenAPI 3.0.3 spec from a `db.yml` file without starting a server.
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
npx @yrest/cli openapi db.yml # writes openapi.yaml
|
|
152
|
+
npx @yrest/cli openapi db.yml --format json # writes openapi.json
|
|
153
|
+
npx @yrest/cli openapi db.yml --stdout # prints to stdout
|
|
154
|
+
npx @yrest/cli openapi db.yml --output api-spec.yaml # custom output path
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
| Flag | Default | Description |
|
|
158
|
+
| ----------------- | ----------- | ----------------------------------------------------------- |
|
|
159
|
+
| `--output <file>` | _(auto)_ | Output file path (default: `openapi.yaml` / `openapi.json`) |
|
|
160
|
+
| `--format <fmt>` | `yaml` | Output format: `yaml` or `json` |
|
|
161
|
+
| `--stdout` | `false` | Print to stdout instead of writing a file |
|
|
162
|
+
| `--base <base>` | _(none)_ | Base path prefix applied to all routes |
|
|
163
|
+
| `--port <port>` | `3070` | Server port shown in the `servers` block |
|
|
164
|
+
| `--host <host>` | `localhost` | Server host shown in the `servers` block |
|
|
165
|
+
| `--title <title>` | `yRest API` | API title for the `info` block |
|
|
166
|
+
|
|
167
|
+
The spec is also available live at `GET /_openapi` (YAML) and `GET /_openapi.json` (JSON) while the server is running — no extra flag or config needed.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
143
171
|
### `serve`
|
|
144
172
|
|
|
145
173
|
Starts the mock server.
|
|
@@ -215,6 +243,46 @@ Each top-level key becomes a resource with full CRUD endpoints.
|
|
|
215
243
|
|
|
216
244
|
---
|
|
217
245
|
|
|
246
|
+
## Field annotations (`_schema`)
|
|
247
|
+
|
|
248
|
+
Add a `_schema` block to `db.yml` to declare field-level metadata per collection. Used by the OpenAPI generator to produce accurate schemas — has no effect on runtime CRUD behavior.
|
|
249
|
+
|
|
250
|
+
```yaml
|
|
251
|
+
_schema:
|
|
252
|
+
users:
|
|
253
|
+
name: required # shorthand: marks field as required
|
|
254
|
+
email:
|
|
255
|
+
required: true
|
|
256
|
+
format: email
|
|
257
|
+
age:
|
|
258
|
+
type: integer
|
|
259
|
+
role:
|
|
260
|
+
type: string
|
|
261
|
+
enum: [admin, editor, viewer]
|
|
262
|
+
default: viewer
|
|
263
|
+
description: User role
|
|
264
|
+
|
|
265
|
+
users:
|
|
266
|
+
- id: 1
|
|
267
|
+
name: Ana
|
|
268
|
+
email: ana@test.com
|
|
269
|
+
age: 28
|
|
270
|
+
role: admin
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
| Key | Type | Description |
|
|
274
|
+
| ------------- | --------- | ----------------------------------------------------------------------------------------- |
|
|
275
|
+
| `required` | `boolean` | Marks the field as required in the OpenAPI schema |
|
|
276
|
+
| `type` | `string` | Overrides the inferred type (`string`, `integer`, `number`, `boolean`, `array`, `object`) |
|
|
277
|
+
| `format` | `string` | OpenAPI format hint (`email`, `date`, `date-time`, `uuid`, `uri`, …) |
|
|
278
|
+
| `enum` | `array` | Restricts the field to a fixed set of values |
|
|
279
|
+
| `description` | `string` | Field description included in the OpenAPI schema |
|
|
280
|
+
| `default` | `any` | Default value shown in the OpenAPI schema |
|
|
281
|
+
|
|
282
|
+
Fields not listed in `_schema` are inferred from the first items in the collection and treated as optional. `_schema` itself is excluded from the generated REST resources.
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
218
286
|
## Generated endpoints
|
|
219
287
|
|
|
220
288
|
For each resource in `db.yml`:
|
|
@@ -405,10 +473,6 @@ A child record holds a foreign key pointing to a parent. The string shorthand im
|
|
|
405
473
|
_rel:
|
|
406
474
|
posts:
|
|
407
475
|
userId: users # shorthand: many2one
|
|
408
|
-
# equivalent to:
|
|
409
|
-
# userId:
|
|
410
|
-
# type: many2one
|
|
411
|
-
# target: users
|
|
412
476
|
```
|
|
413
477
|
|
|
414
478
|
### `one2one`
|
|
@@ -419,8 +483,8 @@ One child record belongs to exactly one parent, and a parent has at most one chi
|
|
|
419
483
|
_rel:
|
|
420
484
|
profiles:
|
|
421
485
|
userId:
|
|
422
|
-
|
|
423
|
-
|
|
486
|
+
_type: one2one
|
|
487
|
+
_target: users
|
|
424
488
|
```
|
|
425
489
|
|
|
426
490
|
### `many2many`
|
|
@@ -431,11 +495,11 @@ Two collections are linked through a pivot (join) table:
|
|
|
431
495
|
_rel:
|
|
432
496
|
posts:
|
|
433
497
|
tags:
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
498
|
+
_type: many2many
|
|
499
|
+
_target: tags
|
|
500
|
+
_through: post_tags # pivot collection
|
|
501
|
+
_foreignKey: postId
|
|
502
|
+
_otherKey: tagId
|
|
439
503
|
|
|
440
504
|
post_tags:
|
|
441
505
|
- id: 1
|
|
@@ -443,31 +507,65 @@ post_tags:
|
|
|
443
507
|
tagId: 2
|
|
444
508
|
```
|
|
445
509
|
|
|
446
|
-
### Auto-embedding with `
|
|
510
|
+
### Auto-embedding with `_nested: true`
|
|
447
511
|
|
|
448
|
-
Add `
|
|
512
|
+
Add `_nested: true` to any relation to embed the related data automatically in every GET response, without needing `?_expand` or `?_embed`:
|
|
449
513
|
|
|
450
514
|
```yaml
|
|
451
515
|
_rel:
|
|
452
516
|
posts:
|
|
453
517
|
userId:
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
518
|
+
_type: many2one
|
|
519
|
+
_target: users
|
|
520
|
+
_nested: true # user object embedded in every /posts response
|
|
457
521
|
tags:
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
522
|
+
_type: many2many
|
|
523
|
+
_target: tags
|
|
524
|
+
_through: post_tags
|
|
525
|
+
_foreignKey: postId
|
|
526
|
+
_otherKey: tagId
|
|
527
|
+
_nested: true # tags array embedded in every /posts response
|
|
464
528
|
```
|
|
465
529
|
|
|
466
530
|
```
|
|
467
531
|
GET /posts/1 → { id: 1, title: "...", userId: 1, user: { ... }, tags: [...] }
|
|
468
532
|
```
|
|
469
533
|
|
|
470
|
-
`many2one` / `one2one` with `
|
|
534
|
+
`many2one` / `one2one` with `_nested: true` embed the parent object under the derived key (`userId` → `user`). The original FK field is preserved. `many2many` with `_nested: true` embeds the resolved target array under the alias key.
|
|
535
|
+
|
|
536
|
+
### Compact DSL syntax
|
|
537
|
+
|
|
538
|
+
Relations can also be declared using a compact string format — useful when you want to express type, target, foreign key and cardinality in a single line:
|
|
539
|
+
|
|
540
|
+
```yaml
|
|
541
|
+
_rel:
|
|
542
|
+
payments:
|
|
543
|
+
bookingId: "m2o:bookings[1..1->0..n]" # type:target[carDirect->carInverse]
|
|
544
|
+
userId: "m2o:users[1..1->0..n]+nested" # +nested flag auto-embeds on every GET
|
|
545
|
+
|
|
546
|
+
profiles:
|
|
547
|
+
userId: "o2o:users[1..1->1..1]"
|
|
548
|
+
|
|
549
|
+
posts:
|
|
550
|
+
authorId: "m2o:users@userId[1..1->0..n]" # @foreignKey when field name ≠ FK column
|
|
551
|
+
|
|
552
|
+
tags:
|
|
553
|
+
posts: "m2m:posts@post_tags(postId,tagId)[0..n->0..n]" # m2m with pivot
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
**Type aliases:**
|
|
557
|
+
|
|
558
|
+
| Alias | Full name |
|
|
559
|
+
| ----- | ----------- |
|
|
560
|
+
| `m2o` | `many2one` |
|
|
561
|
+
| `o2o` | `one2one` |
|
|
562
|
+
| `m2m` | `many2many` |
|
|
563
|
+
|
|
564
|
+
**Cardinality notation:** `[carDirect->carInverse]` — format `min..max` where min is `0` or `1` and max is `1` or `n`. Both segments are optional: omitting them applies defaults (`1..1->1..n` for `m2o`, `1..1->1..1` for `o2o`, `0..n->0..n` for `m2m`).
|
|
565
|
+
|
|
566
|
+
**`+nested` flag:** appended at the end of any DSL string, equivalent to `_nested: true`.
|
|
567
|
+
|
|
568
|
+
The three forms — shorthand string, compact DSL, and verbose object — are fully interchangeable and can be mixed freely within the same `_rel` block.
|
|
471
569
|
|
|
472
570
|
### What relations enable
|
|
473
571
|
|
|
@@ -815,15 +913,22 @@ Useful for test suites that need a clean reset between runs or demos that need a
|
|
|
815
913
|
|
|
816
914
|
---
|
|
817
915
|
|
|
818
|
-
##
|
|
916
|
+
## Meta endpoints
|
|
917
|
+
|
|
918
|
+
Every running server exposes the following meta endpoints without any extra configuration:
|
|
819
919
|
|
|
820
|
-
|
|
920
|
+
| Endpoint | Description |
|
|
921
|
+
| -------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
922
|
+
| `GET /_about` | Self-contained HTML page listing all endpoints, modes, query params and ready-to-run `curl` examples |
|
|
923
|
+
| `GET /_openapi` | OpenAPI 3.0.3 spec in YAML format — regenerated on every request |
|
|
924
|
+
| `GET /_openapi.json` | OpenAPI 3.0.3 spec in JSON format |
|
|
821
925
|
|
|
822
926
|
```bash
|
|
823
927
|
open http://localhost:3070/_about
|
|
928
|
+
curl http://localhost:3070/_openapi.json | npx swagger-ui-watcher -
|
|
824
929
|
```
|
|
825
930
|
|
|
826
|
-
|
|
931
|
+
Both `/_about` and the OpenAPI spec reflect the live storage state and update automatically in watch mode.
|
|
827
932
|
|
|
828
933
|
---
|
|
829
934
|
|
|
@@ -1065,7 +1170,7 @@ const server = createYrestServer({
|
|
|
1065
1170
|
| Visual panel (`/_panel`) | 🔜 |
|
|
1066
1171
|
| Programmatic API for Vitest / Playwright | ✅ |
|
|
1067
1172
|
| Docker image | 🔜 |
|
|
1068
|
-
| OpenAPI export (`yrest openapi db.yml`) |
|
|
1173
|
+
| OpenAPI export (`yrest openapi db.yml`) | ✅ |
|
|
1069
1174
|
| VS Code extension with YAML snippets | 🔜 |
|
|
1070
1175
|
| Request validation with JSON Schema | 🔜 |
|
|
1071
1176
|
| Conditional scenarios (`scenarios:`, `otherwise:`) | ✅ |
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<svg width="314" height="123" viewBox="0 0 314 123" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M0 33.1934H18.9219L41.8701 76.3274L56.5276 47.3956C56.5276 47.3956 59.2983 42.4043 61.6658 38.9502C65.6116 33.1934 69.0931 33.1934 70.0205 33.1934H89.3125C89.3125 33.1934 85.3404 33.1934 81.3936 38.2593C78.8415 41.0227 73.7342 50.4639 73.7342 50.4639L51.122 92.2745C51.122 92.2745 41.6427 111.825 30.5083 118.269C19.0562 124.896 4.49836 122.624 4.49836 122.624L4.58083 107.992C4.58083 107.992 16.0023 109.128 21.5375 105.151C27.3964 100.942 32.8293 92.2745 32.8293 92.2745L0 33.1934Z" fill="white"/>
|
|
3
|
+
<path d="M130.727 47.206C130.727 47.206 140.011 48.1271 140.011 32.9291C140.011 17.731 130.727 17.731 130.727 17.731H87.3238L67.595 17.731V0L130.727 0C130.727 0 159.74 -1.90735e-05 159.74 32.9291C159.74 65.8581 130.727 64.4765 130.727 64.4765L157.651 110.761H132.12L105.892 64.4765L83.8898 64.2463C83.8898 64.2463 87.3997 54.8052 89.9518 52.0418C93.8986 46.9759 97.4065 46.9759 97.4065 46.9759L130.727 47.206Z" fill="url(#paint0_linear_393_1348)"/>
|
|
4
|
+
<path d="M188.11 113.342C183.382 113.342 179.197 112.351 175.555 110.371C171.976 108.326 169.165 105.483 167.12 101.841C165.139 98.1345 164.149 93.7896 164.149 88.8057V87.6556C164.149 82.6717 165.139 78.3587 167.12 74.7166C169.101 71.0107 171.88 68.1673 175.459 66.1865C179.037 64.1418 183.19 63.1195 187.918 63.1195C192.583 63.1195 196.64 64.1738 200.091 66.2823C203.541 68.327 206.225 71.2023 208.142 74.9083C210.058 78.5504 211.017 82.7995 211.017 87.6556V91.7769H176.417C176.545 95.0356 177.759 97.6873 180.059 99.7319C182.359 101.777 185.171 102.799 188.493 102.799C191.88 102.799 194.372 102.064 195.969 100.595C197.567 99.1249 198.781 97.4956 199.611 95.7065L209.483 100.882C208.589 102.543 207.279 104.364 205.554 106.345C203.892 108.262 201.656 109.923 198.845 111.329C196.033 112.671 192.455 113.342 188.11 113.342ZM176.513 82.7675H198.749C198.493 80.02 197.375 77.8156 195.394 76.1543C193.477 74.493 190.953 73.6623 187.823 73.6623C184.564 73.6623 181.976 74.493 180.059 76.1543C178.142 77.8156 176.96 80.02 176.513 82.7675ZM241.51 113.342C235.312 113.342 230.232 112 226.27 109.316C222.309 106.633 219.913 102.799 219.082 97.8151L230.2 94.9397C230.647 97.1761 231.382 98.9332 232.404 100.211C233.491 101.489 234.8 102.416 236.334 102.991C237.931 103.502 239.657 103.757 241.51 103.757C244.321 103.757 246.398 103.278 247.739 102.32C249.081 101.297 249.752 100.051 249.752 98.5818C249.752 97.1122 249.113 95.994 247.835 95.2273C246.557 94.3966 244.513 93.7257 241.701 93.2145L239.018 92.7353C235.695 92.0964 232.66 91.2338 229.912 90.1475C227.165 88.9974 224.96 87.4319 223.299 85.4512C221.638 83.4704 220.807 80.9145 220.807 77.7836C220.807 73.0553 222.532 69.4452 225.983 66.9532C229.433 64.3974 233.97 63.1195 239.593 63.1195C244.896 63.1195 249.305 64.3016 252.819 66.6657C256.333 69.0299 258.634 72.1288 259.72 75.9626L248.506 79.413C247.995 76.9849 246.941 75.2597 245.343 74.2374C243.81 73.2151 241.893 72.7039 239.593 72.7039C237.292 72.7039 235.535 73.1192 234.321 73.9499C233.107 74.7166 232.5 75.8029 232.5 77.2086C232.5 78.7421 233.139 79.8922 234.417 80.659C235.695 81.3618 237.42 81.9049 239.593 82.2883L242.276 82.7675C245.854 83.4065 249.081 84.2691 251.957 85.3553C254.896 86.3777 257.196 87.8792 258.857 89.86C260.583 91.7769 261.445 94.3966 261.445 97.7192C261.445 102.703 259.624 106.569 255.982 109.316C252.404 112 247.58 113.342 241.51 113.342ZM289.302 112C286.171 112 283.615 111.042 281.635 109.125C279.718 107.144 278.759 104.524 278.759 101.265V74.4291H266.875V64.4613H278.759V49.7013H290.836V64.4613H303.87V74.4291H290.836V99.1569C290.836 101.074 291.73 102.032 293.519 102.032H302.72V112H289.302Z" fill="#1F72F5"/>
|
|
5
|
+
<path d="M71.2803 33.5454C70.3529 33.5454 66.8714 33.5454 62.9256 39.3022C60.5581 42.7563 57.7874 47.7476 57.7874 47.7476L43.1299 76.6794M71.2803 33.5454C82.6534 33.5454 119.805 33.5454 119.805 33.5454H71.2803Z" stroke="url(#paint1_linear_393_1348)" stroke-width="3.99351" stroke-linecap="round"/>
|
|
6
|
+
<circle cx="86.26" cy="33.5456" r="4.79221" fill="#3480F6"/>
|
|
7
|
+
<path d="M46.3246 78.2727C46.3246 80.9193 44.1791 83.0649 41.5324 83.0649C38.8858 83.0649 36.7402 80.9193 36.7402 78.2727C36.7402 75.626 38.8858 73.4805 41.5324 73.4805C44.1791 73.4805 46.3246 75.626 46.3246 78.2727Z" fill="#12438F"/>
|
|
8
|
+
<circle cx="119.805" cy="33.5456" r="4.79221" fill="#C9DCFB"/>
|
|
9
|
+
<defs>
|
|
10
|
+
<linearGradient id="paint0_linear_393_1348" x1="79.8701" y1="0" x2="79.8701" y2="123" gradientUnits="userSpaceOnUse">
|
|
11
|
+
<stop stop-color="#0A4EBA"/>
|
|
12
|
+
<stop offset="0.399038" stop-color="#1F72F5"/>
|
|
13
|
+
</linearGradient>
|
|
14
|
+
<linearGradient id="paint1_linear_393_1348" x1="125.396" y1="32.7467" x2="44.7273" y2="75.0779" gradientUnits="userSpaceOnUse">
|
|
15
|
+
<stop stop-color="#C9DCFB"/>
|
|
16
|
+
<stop offset="0.5" stop-color="#1F72F5"/>
|
|
17
|
+
<stop offset="1" stop-color="#12438F"/>
|
|
18
|
+
</linearGradient>
|
|
19
|
+
</defs>
|
|
20
|
+
</svg>
|
|
Binary file
|
|
Binary file
|