fastapi-voyager 0.12.4__py3-none-any.whl → 0.12.6__py3-none-any.whl

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.
@@ -1,2 +1,2 @@
1
1
  __all__ = ["__version__"]
2
- __version__ = "0.12.4"
2
+ __version__ = "0.12.6"
@@ -10,7 +10,7 @@ export default defineComponent({
10
10
  },
11
11
  template: `
12
12
  <div>
13
- <p>Count: {{ store.state.count }}</p>
13
+ <p>Count: {{ store.state.item.count }}</p>
14
14
  <button @click="store.mutations.increment()">Add</button>
15
15
  </div>
16
16
  `
@@ -14,7 +14,6 @@ export default defineComponent({
14
14
  name: "SchemaFieldFilter",
15
15
  props: {
16
16
  schemaName: { type: String, default: null }, // external injection triggers auto-query
17
- // externally provided schemas dict (state.rawSchemasFull): { [id]: schema }
18
17
  schemas: { type: Object, default: () => ({}) },
19
18
  },
20
19
  emits: ["queried", "close"],
@@ -9,14 +9,31 @@ export class GraphUI {
9
9
  this._init();
10
10
  }
11
11
 
12
- _highlight() {
12
+ _highlight(mode = "bidirectional") {
13
13
  let highlightedNodes = $();
14
14
  for (const selection of this.currentSelection) {
15
- const nodes = this._getAffectedNodes(selection.set, "bidirectional");
15
+ const nodes = this._getAffectedNodes(selection.set, mode);
16
16
  highlightedNodes = highlightedNodes.add(nodes);
17
17
  }
18
18
  if (this.gv) {
19
19
  this.gv.highlight(highlightedNodes, true);
20
+ this.gv.bringToFront(highlightedNodes);
21
+ }
22
+ }
23
+
24
+ _highlightEdgeNodes() {
25
+ let highlightedNodes = $();
26
+ const [up, down, edge] = this.currentSelection
27
+ highlightedNodes = highlightedNodes.add(
28
+ this._getAffectedNodes(up.set, up.direction)
29
+ );
30
+ highlightedNodes = highlightedNodes.add(
31
+ this._getAffectedNodes(down.set, down.direction)
32
+ );
33
+ highlightedNodes = highlightedNodes.add(edge.set)
34
+ if (this.gv) {
35
+ this.gv.highlight(highlightedNodes, true);
36
+ this.gv.bringToFront(highlightedNodes);
20
37
  }
21
38
  }
22
39
 
@@ -65,6 +82,7 @@ export class GraphUI {
65
82
  }
66
83
  }
67
84
 
85
+
68
86
  _init() {
69
87
  const self = this;
70
88
  $(this.selector).graphviz({
@@ -82,9 +100,7 @@ export class GraphUI {
82
100
  }
83
101
  const set = $();
84
102
  set.push(this);
85
- // const obj = { set, direction: "bidirectional" };
86
103
  const schemaName = event.currentTarget.dataset.name;
87
- // self.currentSelection = [obj];
88
104
  if (schemaName) {
89
105
  try {
90
106
  self.options.onSchemaClick(schemaName);
@@ -93,6 +109,24 @@ export class GraphUI {
93
109
  }
94
110
  }
95
111
  });
112
+
113
+ self.gv.edges().click(function (event) {
114
+ const up = $();
115
+ const down = $();
116
+ const edge = $();
117
+ const [upStreamNode, downStreamNode] = event.currentTarget.dataset.name.split("->");
118
+ const nodes = self.gv.nodesByName();
119
+ up.push(nodes[upStreamNode]);
120
+ down.push(nodes[downStreamNode]);
121
+ edge.push(this)
122
+ const upObj = { set: up, direction: "upstream" };
123
+ const downObj = { set: down, direction: "downstream" };
124
+ const edgeOjb = { set: edge, direction: "single"};
125
+ self.currentSelection = [upObj, downObj, edgeOjb];
126
+
127
+ self._highlightEdgeNodes();
128
+ })
129
+
96
130
  self.gv.nodes().click(function (event) {
97
131
  const set = $();
98
132
  set.push(this);
@@ -100,7 +134,6 @@ export class GraphUI {
100
134
 
101
135
  const schemaName = event.currentTarget.dataset.name;
102
136
  if (event.shiftKey && self.options.onSchemaClick) {
103
- // try data-name or title text
104
137
  if (schemaName) {
105
138
  try {
106
139
  self.options.onSchemaShiftClick(schemaName);
@@ -119,23 +152,10 @@ export class GraphUI {
119
152
  }
120
153
  });
121
154
 
122
- self.gv.clusters().click(function (event) {
123
- const set = $();
124
- set.push(this);
125
- const obj = { set, direction: "single" };
126
- if (event.ctrlKey || event.metaKey || event.shiftKey) {
127
- self.currentSelection.push(obj);
128
- } else {
129
- self.currentSelection = [obj];
130
- }
131
- self._highlight();
132
- });
133
-
134
- // svg 背景点击高亮清空
135
155
  $(document)
136
156
  .off("click.graphui")
137
157
  .on("click.graphui", function (evt) {
138
- // 如果点击目标不在 graph 容器内,直接退出
158
+ // if outside container, do nothing
139
159
  const graphContainer = $(self.selector)[0];
140
160
  if (
141
161
  !graphContainer ||
@@ -146,9 +166,9 @@ export class GraphUI {
146
166
  }
147
167
 
148
168
  let isNode = false;
149
- const $nodes = self.gv.nodes();
169
+ const $everything = self.gv.$nodes.add(self.gv.$edges).add(self.gv.$clusters);
150
170
  const node = evt.target.parentNode;
151
- $nodes.each(function () {
171
+ $everything.each(function () {
152
172
  if (this === node) {
153
173
  isNode = true;
154
174
  }
@@ -21,6 +21,8 @@
21
21
  url: null,
22
22
  svg: null,
23
23
  shrink: "0.125pt",
24
+ edgeHitPadding: 12,
25
+ pointerCursor: true,
24
26
  tooltips: {
25
27
  init: function ($graph) {
26
28
  var $a = $(this);
@@ -168,9 +170,20 @@
168
170
  var that = this;
169
171
  var options = this.options;
170
172
 
173
+ if (type === "edge" && options.edgeHitPadding) {
174
+ this.ensureEdgeHitArea($el, options.edgeHitPadding);
175
+ }
176
+
177
+ if (options.pointerCursor && (type === "edge" || type === "node")) {
178
+ this.setInteractiveCursor($el, type === "edge");
179
+ }
180
+
171
181
  // save the colors of the paths, ellipses and polygons
172
182
  $el.find("polygon, ellipse, path").each(function () {
173
183
  var $this = $(this);
184
+ if ($this.attr("data-graphviz-hitbox") === "true") {
185
+ return;
186
+ }
174
187
  // save original colors
175
188
  $this.data("graphviz.svg.color", {
176
189
  fill: $this.attr("fill"),
@@ -314,6 +327,69 @@
314
327
  }
315
328
  };
316
329
 
330
+ GraphvizSvg.prototype.ensureEdgeHitArea = function ($edge, padding) {
331
+ var width = parseFloat(padding);
332
+ if (!isFinite(width) || width <= 0) {
333
+ return;
334
+ }
335
+ var $paths = $edge
336
+ .children("path")
337
+ .filter(function () {
338
+ return $(this).attr("data-graphviz-hitbox") !== "true";
339
+ });
340
+ if (!$paths.length) {
341
+ return;
342
+ }
343
+ $paths.each(function () {
344
+ var $path = $(this);
345
+ var $existing = $path.prev('[data-graphviz-hitbox="true"]');
346
+ if ($existing.length) {
347
+ $existing.attr("stroke-width", width);
348
+ return;
349
+ }
350
+ var clone = this.cloneNode(false);
351
+
352
+ /**
353
+ * gtp-5-codex:
354
+ * Cloning the edge paths without copying D3’s data binding caused those Cannot
355
+ * read properties of undefined (reading 'key') errors when d3-graphviz re-rendered.
356
+ * I now copy the original path’s bound datum (__data__) onto the transparent hitbox
357
+ * clone inside ensureEdgeHitArea, so D3 still finds the expected metadata.
358
+ */
359
+ if (this.__data__) {
360
+ clone.__data__ = this.__data__;
361
+ }
362
+
363
+ var $clone = $(clone);
364
+ $clone.attr({
365
+ "data-graphviz-hitbox": "true",
366
+ stroke: "transparent",
367
+ fill: "none",
368
+ "stroke-width": width,
369
+ });
370
+ $clone.attr("pointer-events", "stroke");
371
+ $clone.css("pointer-events", "stroke");
372
+ if (!$clone.attr("stroke-linecap")) {
373
+ $clone.attr("stroke-linecap", $path.attr("stroke-linecap") || "round");
374
+ }
375
+ $clone.insertBefore($path);
376
+ });
377
+ };
378
+
379
+ GraphvizSvg.prototype.setInteractiveCursor = function ($el, isEdge) {
380
+ $el.css("cursor", "pointer");
381
+ var selectors = "path, polygon, ellipse, rect, text";
382
+ $el.find(selectors).each(function () {
383
+ $(this).css("cursor", "pointer");
384
+ });
385
+ if (isEdge) {
386
+ $el.children('[data-graphviz-hitbox="true"]').css("cursor", "pointer");
387
+ }
388
+ $el.find("a").each(function () {
389
+ $(this).css("cursor", "pointer");
390
+ });
391
+ };
392
+
317
393
  GraphvizSvg.prototype.convertToPx = function (val) {
318
394
  var retval = val;
319
395
  if (typeof val == "string") {
@@ -372,6 +448,9 @@
372
448
  var bg = this.$element.css("background");
373
449
  $el.find("polygon, ellipse, path").each(function () {
374
450
  var $this = $(this);
451
+ if ($this.attr("data-graphviz-hitbox") === "true") {
452
+ return;
453
+ }
375
454
  var color = $this.data("graphviz.svg.color");
376
455
  if (color.fill && color.fill != "none") {
377
456
  $this.attr("fill", getColor(color.fill, bg)); // don't set fill if it's a path
@@ -386,6 +465,9 @@
386
465
  GraphvizSvg.prototype.restoreElement = function ($el) {
387
466
  $el.find("polygon, ellipse, path").each(function () {
388
467
  var $this = $(this);
468
+ if ($this.attr("data-graphviz-hitbox") === "true") {
469
+ return;
470
+ }
389
471
  var color = $this.data("graphviz.svg.color");
390
472
  if (color.fill && color.fill != "none") {
391
473
  $this.attr("fill", color.fill); // don't set fill if it's a path
@@ -105,13 +105,13 @@
105
105
  >
106
106
  <q-icon class="q-mr-sm" name="satellite_alt"></q-icon>
107
107
  <span> FastAPI Voyager </span>
108
- <span v-if="state.version" style="font-size: 12px; margin-left: 8px; font-weight: normal;">{{ state.version }}</span>
108
+ <span v-if="store.state.version" style="font-size: 12px; margin-left: 8px; font-weight: normal;">{{ store.state.version }}</span>
109
109
  </div>
110
110
  <div class="col-auto" style="font-size: 16px">
111
111
  <q-option-group
112
112
  style="margin-left: 80px"
113
- v-model="state.showFields"
114
- :options="state.fieldOptions"
113
+ v-model="store.state.filter.showFields"
114
+ :options="store.state.fieldOptions"
115
115
  @update:model-value="(val) => toggleShowField(val)"
116
116
  color="primary"
117
117
  type="radio"
@@ -137,7 +137,7 @@
137
137
  flat
138
138
  label="Search"
139
139
  class="q-mr-md"
140
- @click="showDialog()"
140
+ @click="showSearchDialog()"
141
141
  />
142
142
  </div>
143
143
  <div class="col-auto">
@@ -176,8 +176,8 @@
176
176
  </q-header>
177
177
 
178
178
  <q-drawer
179
- v-model="state.detailDrawer"
180
- :width="state.drawerWidth"
179
+ v-model="store.state.rightDrawer.drawer"
180
+ :width="store.state.rightDrawer.width"
181
181
  side="right"
182
182
  style="border-left: 1px solid #888;"
183
183
  bordered
@@ -201,7 +201,7 @@
201
201
 
202
202
  <div style="z-index: 11; position: absolute; left: -17px; top: 9px">
203
203
  <q-btn
204
- @click="state.detailDrawer = !state.detailDrawer"
204
+ @click="store.state.rightDrawer.drawer = !store.state.rightDrawer.drawer"
205
205
  round
206
206
  unelevated
207
207
  color="primary"
@@ -210,14 +210,14 @@
210
210
  />
211
211
  </div>
212
212
  <schema-code-display
213
- :schema-name="schemaCodeName"
214
- :schemas="state.rawSchemasFull"
213
+ :schema-name="store.state.schemaDetail.schemaCodeName"
214
+ :schemas="store.state.graph.schemaMap"
215
215
  />
216
216
  </q-drawer>
217
217
 
218
218
  <q-page-container>
219
219
  <q-splitter
220
- v-model="state.splitter"
220
+ v-model="store.state.leftPanel.width"
221
221
  unit="px"
222
222
  :limits="[200, 800]"
223
223
  class="adjust-fit"
@@ -236,12 +236,12 @@
236
236
  <q-scroll-area class="fit">
237
237
  <q-list dense separator>
238
238
  <q-expansion-item
239
- v-for="tag in state.rawTags"
239
+ v-for="tag in store.state.leftPanel.tags"
240
240
  :key="tag.name"
241
241
  expand-separator
242
- :model-value="state._tag === tag.name"
242
+ :model-value="store.state.leftPanel._tag === tag.name"
243
243
  @update:model-value="(val) => toggleTag(tag.name, val)"
244
- :header-class="state.tag === tag.name ? 'text-primary text-bold' : ''"
244
+ :header-class="store.state.leftPanel.tag === tag.name ? 'text-primary text-bold' : ''"
245
245
  content-class="q-pa-none"
246
246
  >
247
247
  <template #header>
@@ -249,21 +249,21 @@
249
249
  <q-icon
250
250
  style="vertical-align: top;"
251
251
  class="q-mr-sm"
252
- :name="state.tag == tag.name ? 'folder' : 'folder_open'"
252
+ :name="store.state.leftPanel.tag == tag.name ? 'folder' : 'folder_open'"
253
253
  ></q-icon>
254
254
  <span>{{ tag.name }} <q-chip style="position:relative; top: -1px;" class="q-ml-md" dense>{{ tag.routes.length }}</q-chip></span>
255
- <a v-if="state._tag == tag.name" target="_blank" class="q-ml-sm" v-if="state.swaggerUrl" :href="state.swaggerUrl + '#/' + tag.name">
255
+ <a v-if="store.state.leftPanel._tag == tag.name" target="_blank" class="q-ml-sm" v-if="store.state.swagger.url" :href="store.state.swagger.url + '#/' + tag.name">
256
256
  <q-icon color="primary" size="" name="link" title="open in swagger"></q-icon>
257
257
  </a>
258
258
  </div>
259
259
  </template>
260
260
  <q-list separator style="overflow: auto; max-height: 60vh;">
261
261
  <q-item
262
- v-for="route in (state.hidePrimitiveRoute ? tag.routes.filter(r => !r.is_primitive) :tag.routes || [])"
262
+ v-for="route in (store.state.filter.hidePrimitiveRoute ? tag.routes.filter(r => !r.is_primitive) :tag.routes || [])"
263
263
  :key="route.id"
264
264
  clickable
265
265
  v-ripple
266
- :active="state.routeId === route.id"
266
+ :active="store.state.leftPanel.routeId === route.id"
267
267
  active-class=""
268
268
  @click="selectRoute(route.id)"
269
269
  >
@@ -274,7 +274,7 @@
274
274
  name="data_object"
275
275
  ></q-icon>
276
276
  {{ route.name }}
277
- <a v-if="state.routeId == route.id" target="_blank" class="q-ml-md" v-if="state.swaggerUrl" :href="state.swaggerUrl + '#/' + tag.name + '/' + route.unique_id">
277
+ <a v-if="store.state.leftPanel.routeId == route.id" target="_blank" class="q-ml-md" v-if="store.state.swagger.url" :href="store.state.swagger.url + '#/' + tag.name + '/' + route.unique_id">
278
278
  <q-icon color="primary" size="" name="link" title="open in swagger"></q-icon>
279
279
  </a>
280
280
  </span>
@@ -301,19 +301,9 @@
301
301
  <div style="position: absolute; left: 8px; top: 8px; z-index: 10; background: rgba(255,255,255,0.85); border-radius: 4px; padding: 2px 8px;">
302
302
  <div class="q-mt-sm">
303
303
  <q-toggle
304
- v-model="state.focus"
305
- v-show="schemaCodeName"
306
- @update:model-value="val => onFocusChange(val)"
307
- label="Focus"
304
+ v-if="store.state.modeControl.briefModeEnabled"
308
305
  dense
309
- title="pick a schema and toggle focus on to display related nodes only"
310
- />
311
- </div>
312
- <div class="q-mt-sm">
313
- <q-toggle
314
- v-if="state.enableBriefMode"
315
- dense
316
- v-model="state.brief"
306
+ v-model="store.state.filter.brief"
317
307
  label="Brief Mode"
318
308
  @update:model-value="(val) => toggleBrief(val)"
319
309
  title="skip middle classes, config module_prefix to enable it"
@@ -321,7 +311,7 @@
321
311
  </div>
322
312
  <div class="q-mt-sm">
323
313
  <q-toggle
324
- v-model="state.hidePrimitiveRoute"
314
+ v-model="store.state.filter.hidePrimitiveRoute"
325
315
  @update:model-value="(val) => toggleHidePrimitiveRoute(val)"
326
316
  label="Hide Primitive"
327
317
  dense
@@ -330,7 +320,7 @@
330
320
  </div>
331
321
  <div class="q-mt-sm">
332
322
  <q-toggle
333
- v-model="state.showModule"
323
+ v-model="store.state.filter.showModule"
334
324
  @update:model-value="(val) => toggleShowModule(val)"
335
325
  label="Show Module Cluster"
336
326
  dense
@@ -339,17 +329,13 @@
339
329
  </div>
340
330
  <div class="q-mt-sm">
341
331
  <q-toggle
342
- v-model="state.focus"
343
- v-show="schemaCodeName"
332
+ v-model="store.state.modeControl.focus"
333
+ v-show="store.state.schemaDetail.schemaCodeName"
344
334
  @update:model-value="val => onFocusChange(val)"
345
335
  label="Focus"
346
336
  dense
347
337
  title="pick a schema and toggle focus on to display related nodes only"
348
338
  />
349
- </div>
350
- <!-- <div class="q-mt-sm">
351
- <demo-component></demo-component>
352
- </div> -->
353
339
  </div>
354
340
  </div>
355
341
  </template>
@@ -359,95 +345,28 @@
359
345
 
360
346
  <!-- Schema Field Filter Dialog -->
361
347
  <q-dialog
362
- v-model="showSchemaFieldFilter"
348
+ v-model="store.state.searchDialog.show"
363
349
  :persistent="true"
364
350
  :maximized="true"
365
351
  >
366
352
  <schema-field-filter
367
- :schemas="state.rawSchemasFull"
368
- :schema-name="schemaFieldFilterSchema"
369
- @close="showSchemaFieldFilter = false"
353
+ :schemas="store.state.graph.schemaMap"
354
+ :schema-name="store.state.searchDialog.schema"
355
+ @close="store.state.searchDialog.show = false"
370
356
  />
371
357
  </q-dialog>
372
358
 
373
- <q-dialog v-model="showRouteDetail" seamless position="bottom">
359
+ <q-dialog v-model="store.state.routeDetail.show" seamless position="bottom">
374
360
  <q-card style="width: 1100px; max-width: 1100px; max-height: 40vh">
375
361
  <route-code-display
376
- :route-id="routeCodeId"
377
- @close="showRouteDetail=false"
362
+ :route-id="store.state.routeDetail.routeCodeId"
363
+ @close="store.state.routeDetail.show = false"
378
364
  />
379
365
  </q-card>
380
366
  </q-dialog>
381
367
 
382
- <!-- Dump Core Data Dialog -->
383
- <q-dialog v-model="showDumpDialog" :maximized="true" :persistent="false">
384
- <div style="height: 100%; position: relative; background: #fff">
385
- <q-btn
386
- flat
387
- dense
388
- round
389
- icon="content_copy"
390
- aria-label="Copy"
391
- @click="copyDumpJson"
392
- style="
393
- position: absolute;
394
- top: 6px;
395
- right: 62px;
396
- z-index: 11;
397
- background: rgba(255, 255, 255, 0.85);
398
- "
399
- ></q-btn>
400
- <q-btn
401
- flat
402
- dense
403
- round
404
- icon="close"
405
- aria-label="Close"
406
- @click="showDumpDialog = false"
407
- style="
408
- position: absolute;
409
- top: 6px;
410
- right: 6px;
411
- z-index: 11;
412
- background: rgba(255, 255, 255, 0.85);
413
- "
414
- ></q-btn>
415
- <div>
416
- <pre
417
- style="padding: 20px; overflow: auto"
418
- ><code>{{ dumpJson }}</code></pre>
419
- </div>
420
- </div>
421
- </q-dialog>
422
-
423
- <!-- Import Core Data Dialog -->
424
- <q-dialog v-model="showImportDialog" :persistent="true">
425
- <q-card style="min-width: 70vw; max-width: 90vw">
426
- <q-card-section class="text-h6">Import core data JSON</q-card-section>
427
- <q-card-section>
428
- <q-btn color="primary" label="Render" @click="onImportConfirm" />
429
- </q-card-section>
430
- <q-card-section>
431
- <q-input
432
- v-model="importJsonText"
433
- type="textarea"
434
- autogrow
435
- filled
436
- label="Paste JSON here"
437
- />
438
- </q-card-section>
439
- </q-card>
440
- </q-dialog>
441
-
442
- <!-- Render Graph Dialog (from imported core data) -->
443
- <q-dialog v-model="showRenderGraph" :maximized="true" :persistent="false">
444
- <render-graph
445
- :core-data="renderCoreData"
446
- @close="showRenderGraph = false"
447
- />
448
- </q-dialog>
449
368
  </div>
450
- <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
369
+ <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
451
370
  <script src="fastapi-voyager-static/quasar.min.js"></script>
452
371
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js" integrity="sha512-egJ/Y+22P9NQ9aIyVCh0VCOsfydyn8eNmqBy+y2CnJG+fpRIxXMS6jbWP8tVKp0jp+NO5n8WtMUAnNnGoJKi4w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
453
372
  <script
@@ -1,12 +1,96 @@
1
- const { reactive, watch, ref } = window.Vue;
1
+ const { reactive } = window.Vue;
2
2
 
3
3
  const state = reactive({
4
- count: 0
4
+ item: {
5
+ count: 0
6
+ },
7
+
8
+ version: '',
9
+
10
+ swagger: {
11
+ url: ''
12
+ },
13
+
14
+ rightDrawer: {
15
+ drawer: false,
16
+ width: 300
17
+ },
18
+
19
+ fieldOptions: [
20
+ { label: "No field", value: "single" },
21
+ { label: "Object fields", value: "object" },
22
+ { label: "All fields", value: "all" },
23
+ ],
24
+
25
+ // tags and routes
26
+ leftPanel: {
27
+ width: 300,
28
+ tags: null,
29
+ tag: null,
30
+ _tag: null,
31
+ routeId: null,
32
+ },
33
+
34
+ graph: {
35
+ schemaId: null,
36
+ schemaKeys: new Set(),
37
+ schemaMap: {},
38
+ routeItems: []
39
+ },
40
+
41
+ leftPanelFiltered: {
42
+
43
+ },
44
+
45
+ // schema options, schema, fields
46
+ search: {
47
+
48
+ },
49
+
50
+
51
+ // route information
52
+ routeDetail: {
53
+ show: false,
54
+ routeCodeId: ''
55
+ },
56
+
57
+ // schema information
58
+ schemaDetail: {
59
+ show: false,
60
+ schemaCodeName: '',
61
+ },
62
+
63
+ searchDialog: {
64
+ show: false,
65
+ schema: null
66
+ },
67
+
68
+ // global status
69
+ status: {
70
+ generating: false,
71
+ loading: false,
72
+ initializing: true,
73
+ },
74
+
75
+ // brief, hide primitive ...
76
+ modeControl: {
77
+ focus: false, // control the schema param
78
+ briefModeEnabled: false, // show brief mode toggle
79
+ },
80
+
81
+ // api filters
82
+ filter: {
83
+ hidePrimitiveRoute: false,
84
+ showFields: 'object',
85
+ brief: false,
86
+ showModule: true,
87
+ }
88
+
5
89
  })
6
90
 
7
91
  const mutations = {
8
92
  increment() {
9
- state.count += 1
93
+ state.item.count += 1
10
94
  }
11
95
  }
12
96
 
@@ -4,67 +4,14 @@ import RouteCodeDisplay from "./component/route-code-display.js";
4
4
  import Demo from './component/demo.js'
5
5
  import RenderGraph from "./component/render-graph.js";
6
6
  import { GraphUI } from "./graph-ui.js";
7
- const { createApp, reactive, onMounted, watch, ref } = window.Vue;
7
+ import { store } from './store.js'
8
+
9
+ const { createApp, onMounted, ref } = window.Vue;
8
10
 
9
11
  const app = createApp({
10
12
  setup() {
11
- const state = reactive({
12
- // options and selections
13
- tag: null, // picked tag
14
- _tag: null, // display tag
15
- routeId: null, // picked route
16
- schemaId: null, // picked schema
17
- showFields: "object",
18
- fieldOptions: [
19
- { label: "No field", value: "single" },
20
- { label: "Object fields", value: "object" },
21
- { label: "All fields", value: "all" },
22
- ],
23
- enableBriefMode: false,
24
- brief: false,
25
- focus: false,
26
- hidePrimitiveRoute: false,
27
- generating: false,
28
- swaggerUrl: null,
29
- rawTags: [], // [{ name, routes: [{ id, name }] }]
30
- rawSchemas: new Set(), // [{ name, id }]
31
- rawSchemasFull: {}, // full schemas dict: { [schema.id]: schema }
32
- initializing: true,
33
- // Splitter size (left panel width in px)
34
- splitter: 300,
35
- detailDrawer: false,
36
- drawerWidth: 300, // drawer 宽度
37
- version: "", // version from backend
38
- showModule: true,
39
- });
40
-
41
- const showDetail = ref(false);
42
- const showSchemaFieldFilter = ref(false);
43
-
44
- const showDumpDialog = ref(false);
45
- const dumpJson = ref("");
46
- const showImportDialog = ref(false);
47
- const importJsonText = ref("");
48
-
49
- const showRenderGraph = ref(false);
50
-
51
- const renderCoreData = ref(null);
52
-
53
- const schemaName = ref(""); // used by detail dialog
54
- const schemaFieldFilterSchema = ref(null); // external schemaName for schema-field-filter
55
- const schemaCodeName = ref("");
56
- const routeCodeId = ref("");
57
- const showRouteDetail = ref(false);
58
-
59
13
  let graphUI = null;
60
14
 
61
- function openDetail() {
62
- showDetail.value = true;
63
- }
64
- function closeDetail() {
65
- showDetail.value = false;
66
- }
67
-
68
15
  function readQuerySelection() {
69
16
  if (typeof window === "undefined") {
70
17
  return { tag: null, route: null };
@@ -78,7 +25,7 @@ const app = createApp({
78
25
 
79
26
  function findTagByRoute(routeId) {
80
27
  return (
81
- state.rawTags.find((tag) =>
28
+ store.state.leftPanel.tags.find((tag) =>
82
29
  (tag.routes || []).some((route) => route.id === routeId)
83
30
  )?.name || null
84
31
  );
@@ -89,13 +36,13 @@ const app = createApp({
89
36
  return;
90
37
  }
91
38
  const params = new URLSearchParams(window.location.search);
92
- if (state.tag) {
93
- params.set("tag", state.tag);
39
+ if (store.state.leftPanel.tag) {
40
+ params.set("tag", store.state.leftPanel.tag);
94
41
  } else {
95
42
  params.delete("tag");
96
43
  }
97
- if (state.routeId) {
98
- params.set("route", state.routeId);
44
+ if (store.state.leftPanel.routeId) {
45
+ params.set("route", store.state.leftPanel.routeId);
99
46
  } else {
100
47
  params.delete("route");
101
48
  }
@@ -108,45 +55,47 @@ const app = createApp({
108
55
 
109
56
  function applySelectionFromQuery(selection) {
110
57
  let applied = false;
111
- if (selection.tag && state.rawTags.some((tag) => tag.name === selection.tag)) {
112
- state.tag = selection.tag;
113
- state._tag = selection.tag;
58
+ if (selection.tag && store.state.leftPanel.tags.some((tag) => tag.name === selection.tag)) {
59
+ store.state.leftPanel.tag = selection.tag;
60
+ store.state.leftPanel._tag = selection.tag;
114
61
  applied = true;
115
62
  }
116
- if (selection.route && state.routeItems?.[selection.route]) {
117
- state.routeId = selection.route;
63
+ if (selection.route && store.state.graph.routeItems?.[selection.route]) {
64
+ store.state.leftPanel.routeId = selection.route;
118
65
  applied = true;
119
66
  const inferredTag = findTagByRoute(selection.route);
120
67
  if (inferredTag) {
121
- state.tag = inferredTag;
122
- state._tag = inferredTag;
68
+ store.state.leftPanel.tag = inferredTag;
69
+ store.state.leftPanel._tag = inferredTag;
123
70
  }
124
71
  }
125
72
  return applied;
126
73
  }
127
74
 
128
75
  async function loadInitial() {
129
- state.initializing = true;
76
+ store.state.initializing = true;
130
77
  try {
131
78
  const res = await fetch("dot");
132
79
  const data = await res.json();
133
- state.rawTags = Array.isArray(data.tags) ? data.tags : [];
80
+ store.state.leftPanel.tags = Array.isArray(data.tags) ? data.tags : [];
81
+
134
82
  const schemasArr = Array.isArray(data.schemas) ? data.schemas : [];
135
83
  // Build dict keyed by id for faster lookups and simpler prop passing
136
- state.rawSchemasFull = Object.fromEntries(
84
+ const schemaMap = Object.fromEntries(
137
85
  schemasArr.map((s) => [s.id, s])
138
86
  );
139
- state.rawSchemas = new Set(Object.keys(state.rawSchemasFull));
140
- state.routeItems = data.tags
87
+ store.state.graph.schemaMap = schemaMap
88
+ store.state.graph.schemaKeys = new Set(Object.keys(schemaMap));
89
+ store.state.graph.routeItems = data.tags
141
90
  .map((t) => t.routes)
142
91
  .flat()
143
92
  .reduce((acc, r) => {
144
93
  acc[r.id] = r;
145
94
  return acc;
146
95
  }, {});
147
- state.enableBriefMode = data.enable_brief_mode || false;
148
- state.version = data.version || "";
149
- state.swaggerUrl = data.swagger_url || null
96
+ store.state.modeControl.briefModeEnabled = data.enable_brief_mode || false;
97
+ store.state.version = data.version || "";
98
+ store.state.swagger.url = data.swagger_url || null
150
99
 
151
100
  const querySelection = readQuerySelection();
152
101
  const restoredFromQuery = applySelectionFromQuery(querySelection);
@@ -163,8 +112,8 @@ const app = createApp({
163
112
  case "empty":
164
113
  return
165
114
  case "first":
166
- state.tag = state.rawTags.length > 0 ? state.rawTags[0].name : null;
167
- state._tag = state.tag;
115
+ store.state.leftPanel.tag = store.state.leftPanel.tags.length > 0 ? store.state.leftPanel.tags[0].name : null;
116
+ store.state.leftPanel._tag = store.state.leftPanel.tag;
168
117
  onGenerate();
169
118
  return
170
119
  }
@@ -173,7 +122,7 @@ const app = createApp({
173
122
  } catch (e) {
174
123
  console.error("Initial load failed", e);
175
124
  } finally {
176
- state.initializing = false;
125
+ store.state.initializing = false;
177
126
  }
178
127
  }
179
128
 
@@ -183,24 +132,24 @@ const app = createApp({
183
132
  } else {
184
133
  await onGenerate(false);
185
134
  setTimeout(() => {
186
- const ele = $(`[data-name='${schemaCodeName.value}'] polygon`);
135
+ const ele = $(`[data-name='${store.state.schemaDetail.schemaCodeName}'] polygon`);
187
136
  ele.dblclick();
188
137
  }, 1);
189
138
  }
190
139
  }
191
140
 
192
141
  async function onGenerate(resetZoom = true) {
193
- const schema_name = state.focus ? schemaCodeName.value : null;
194
- state.generating = true;
142
+ const schema_name = store.state.modeControl.focus ? store.state.schemaDetail.schemaCodeName : null;
143
+ store.state.generating = true;
195
144
  try {
196
145
  const payload = {
197
- tags: state.tag ? [state.tag] : null,
146
+ tags: store.state.leftPanel.tag ? [store.state.leftPanel.tag] : null,
198
147
  schema_name: schema_name || null,
199
- route_name: state.routeId || null,
200
- show_fields: state.showFields,
201
- brief: state.brief,
202
- hide_primitive_route: state.hidePrimitiveRoute,
203
- show_module: state.showModule,
148
+ route_name: store.state.leftPanel.routeId || null,
149
+ show_fields: store.state.filter.showFields,
150
+ brief: store.state.modeControl.brief,
151
+ hide_primitive_route: store.state.filter.hidePrimitiveRoute,
152
+ show_module: store.state.filter.showModule,
204
153
  };
205
154
  const res = await fetch("dot", {
206
155
  method: "POST",
@@ -213,21 +162,21 @@ const app = createApp({
213
162
  if (!graphUI) {
214
163
  graphUI = new GraphUI("#graph", {
215
164
  onSchemaShiftClick: (id) => {
216
- if (state.rawSchemas.has(id)) {
165
+ if (store.state.graph.schemaKeys.has(id)) {
217
166
  resetDetailPanels();
218
- schemaFieldFilterSchema.value = id;
219
- showSchemaFieldFilter.value = true;
167
+ store.state.searchDialog.show = true;
168
+ store.state.searchDialog.schema = id;
220
169
  }
221
170
  },
222
171
  onSchemaClick: (id) => {
223
172
  resetDetailPanels();
224
- if (state.rawSchemas.has(id)) {
225
- schemaCodeName.value = id;
226
- state.detailDrawer = true;
173
+ if (store.state.graph.schemaKeys.has(id)) {
174
+ store.state.schemaDetail.schemaCodeName = id;
175
+ store.state.rightDrawer.drawer = true;
227
176
  }
228
- if (id in state.routeItems) {
229
- routeCodeId.value = id;
230
- showRouteDetail.value = true;
177
+ if (id in store.state.graph.routeItems) {
178
+ store.state.routeDetail.routeCodeId = id;
179
+ store.state.routeDetail.show = true;
231
180
  }
232
181
  },
233
182
  resetCb: () => {
@@ -239,149 +188,95 @@ const app = createApp({
239
188
  } catch (e) {
240
189
  console.error("Generate failed", e);
241
190
  } finally {
242
- state.generating = false;
243
- }
244
- }
245
-
246
- async function onDumpData() {
247
- try {
248
- const payload = {
249
- tags: state.tag ? [state.tag] : null,
250
- schema_name: state.schemaId || null,
251
- route_name: state.routeId || null,
252
- show_fields: state.showFields,
253
- brief: state.brief,
254
- };
255
- const res = await fetch("dot-core-data", {
256
- method: "POST",
257
- headers: { "Content-Type": "application/json" },
258
- body: JSON.stringify(payload),
259
- });
260
- const json = await res.json();
261
- dumpJson.value = JSON.stringify(json, null, 2);
262
- showDumpDialog.value = true;
263
- } catch (e) {
264
- console.error("Dump data failed", e);
191
+ store.state.generating = false;
265
192
  }
266
193
  }
267
194
 
268
- async function copyDumpJson() {
269
- try {
270
- await navigator.clipboard.writeText(dumpJson.value || "");
271
- if (window.Quasar?.Notify) {
272
- window.Quasar.Notify.create({ type: "positive", message: "Copied" });
273
- }
274
- } catch (e) {
275
- console.error("Copy failed", e);
276
- }
277
- }
278
-
279
- function openImportDialog() {
280
- importJsonText.value = "";
281
- showImportDialog.value = true;
282
- }
283
-
284
- async function onImportConfirm() {
285
- let payloadObj = null;
286
- try {
287
- payloadObj = JSON.parse(importJsonText.value || "{}");
288
- } catch (e) {
289
- if (window.Quasar?.Notify) {
290
- window.Quasar.Notify.create({
291
- type: "negative",
292
- message: "Invalid JSON",
293
- });
294
- }
295
- return;
296
- }
297
- // Move the request into RenderGraph component: pass the parsed object and let the component call /dot-render-core-data
298
- renderCoreData.value = payloadObj;
299
- showRenderGraph.value = true;
300
- showImportDialog.value = false;
301
- }
302
-
303
- function showDialog() {
304
- schemaFieldFilterSchema.value = null;
305
- showSchemaFieldFilter.value = true;
195
+ function showSearchDialog() {
196
+ store.state.searchDialog.show = true;
197
+ store.state.searchDialog.schema = null;
306
198
  }
307
199
 
308
200
  function resetDetailPanels() {
309
- state.detailDrawer = false;
310
- showRouteDetail.value = false;
311
- schemaCodeName.value = "";
201
+ store.state.rightDrawer.drawer = false;
202
+ store.state.routeDetail.show = false
203
+ store.state.schemaDetail.schemaCodeName = "";
312
204
  }
313
205
 
314
206
  async function onReset() {
315
- state.tag = null;
316
- state._tag = null;
317
- state.routeId = "";
318
- state.schemaId = null;
207
+ store.state.leftPanel.tag = null;
208
+ store.state.leftPanel._tag = null;
209
+ store.state.leftPanel.routeId = null;
210
+
211
+ store.state.graph.schemaId = null;
212
+
319
213
  // state.showFields = "object";
320
- state.focus = false;
321
- schemaCodeName.value = "";
214
+ store.state.modeControl.focus = false;
215
+ store.state.schemaDetail.schemaCodeName = "";
322
216
  onGenerate();
323
217
  syncSelectionToUrl();
324
218
  }
325
219
 
326
220
  function toggleTag(tagName, expanded = null) {
327
221
  if (expanded === true) {
328
- state._tag = tagName;
329
- state.tag = tagName;
330
- state.routeId = "";
331
- state.focus = false;
332
- schemaCodeName.value = "";
222
+ store.state.leftPanel._tag = tagName;
223
+ store.state.leftPanel.tag = tagName;
224
+ store.state.leftPanel.routeId = "";
225
+
226
+ store.state.modeControl.focus = false;
227
+ store.state.schemaDetail.schemaCodeName = "";
333
228
  onGenerate();
334
229
  } else {
335
- state._tag = null;
230
+ store.state.leftPanel._tag = null;
336
231
  }
337
232
 
338
- state.detailDrawer = false;
339
- showRouteDetail.value = false;
233
+ store.state.rightDrawer.drawer = false;
234
+ store.state.routeDetail.show = false
340
235
  syncSelectionToUrl();
341
236
  }
342
237
 
343
238
  function selectRoute(routeId) {
344
- if (state.routeId === routeId) {
345
- state.routeId = "";
239
+ if (store.state.leftPanel.routeId === routeId) {
240
+ store.state.leftPanel.routeId = "";
346
241
  } else {
347
- state.routeId = routeId;
242
+ store.state.leftPanel.routeId = routeId;
348
243
  }
349
- state.detailDrawer = false;
350
- showRouteDetail.value = false;
351
- state.focus = false;
352
- schemaCodeName.value = "";
244
+ store.state.rightDrawer.drawer = false;
245
+ store.state.routeDetail.show = false
246
+ store.state.modeControl.focus = false;
247
+ store.state.schemaDetail.schemaCodeName = "";
353
248
  onGenerate();
354
249
  syncSelectionToUrl();
355
250
  }
356
251
 
357
252
  function toggleShowModule(val) {
358
- state.showModule = val;
253
+ store.state.filter.showModule = val;
359
254
  onGenerate()
360
255
  }
361
256
 
362
257
  function toggleShowField(field) {
363
- state.showFields = field;
258
+ store.state.filter.showFields = field;
364
259
  onGenerate(false);
365
260
  }
366
261
 
367
262
  function toggleBrief(val) {
368
- state.brief = val;
263
+ store.state.modeControl.brief = val;
369
264
  onGenerate();
370
265
  }
371
266
 
372
267
  function toggleHidePrimitiveRoute(val) {
373
- state.hidePrimitiveRoute = val;
268
+ store.state.filter.hidePrimitiveRoute = val;
374
269
  onGenerate(false);
375
270
  }
376
271
 
377
272
  function startDragDrawer(e) {
378
273
  const startX = e.clientX;
379
- const startWidth = state.drawerWidth;
274
+ const startWidth = store.state.rightDrawer.width;
380
275
 
381
276
  function onMouseMove(moveEvent) {
382
277
  const deltaX = startX - moveEvent.clientX;
383
278
  const newWidth = Math.max(300, Math.min(800, startWidth + deltaX));
384
- state.drawerWidth = newWidth;
279
+ store.state.rightDrawer.width = newWidth;
385
280
  }
386
281
 
387
282
  function onMouseUp() {
@@ -405,39 +300,18 @@ const app = createApp({
405
300
  });
406
301
 
407
302
  return {
408
- state,
303
+ store,
409
304
  toggleTag,
410
305
  toggleBrief,
411
306
  toggleHidePrimitiveRoute,
412
307
  selectRoute,
413
308
  onGenerate,
414
309
  onReset,
415
- showDetail,
416
- showRouteDetail,
417
- openDetail,
418
- closeDetail,
419
- schemaName,
420
- showSchemaFieldFilter,
421
- schemaFieldFilterSchema,
422
- showDialog,
423
- schemaCodeName,
424
- routeCodeId,
425
- // dump/import
426
- showDumpDialog,
427
- dumpJson,
428
- copyDumpJson,
429
- onDumpData,
430
- showImportDialog,
431
- importJsonText,
432
- openImportDialog,
433
- onImportConfirm,
434
- // render graph dialog
435
- showRenderGraph,
436
- renderCoreData,
310
+ showSearchDialog,
437
311
  toggleShowField,
438
312
  startDragDrawer,
439
313
  onFocusChange,
440
- toggleShowModule
314
+ toggleShowModule,
441
315
  };
442
316
  },
443
317
  });
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fastapi-voyager
3
- Version: 0.12.4
3
+ Version: 0.12.6
4
4
  Summary: Visualize FastAPI application's routing tree and dependencies
5
5
  Project-URL: Homepage, https://github.com/allmonday/fastapi-voyager
6
6
  Project-URL: Source, https://github.com/allmonday/fastapi-voyager
@@ -6,21 +6,21 @@ fastapi_voyager/render.py,sha256=7jSChISqTV2agaO55thhwyrOhqVOMux4x7k8rSQROnU,996
6
6
  fastapi_voyager/server.py,sha256=MZNRpcXor2q8Rj3OSf6EH8NkgDChxfzUtnIY8ilRkaY,7053
7
7
  fastapi_voyager/type.py,sha256=7EL1zaIwKVRGpLig7fqaOrZGN5k0Rm31C9COfck3CSs,1750
8
8
  fastapi_voyager/type_helper.py,sha256=JXD_OE_xTARkGjWDsnO_xfvyZ0vcwViYyqCp6oEHBTM,9719
9
- fastapi_voyager/version.py,sha256=_-7Zp-y6CfERg3seD-eKm5cYiJTOf-VWfF-6iV8hzms,49
9
+ fastapi_voyager/version.py,sha256=gCsZjglIeKj6Gr4eowqOBTgIdgKANz1jfSVP3qdkSn4,49
10
10
  fastapi_voyager/voyager.py,sha256=LiRUb0ZG2cfnyY_pwRqoeZjxb6Pu6xy_lqPiMupxoKM,13510
11
- fastapi_voyager/web/graph-ui.js,sha256=7ynB-o8Dse6WHWlp4bmuEfa1pUZJ2YFLJKKXjr4R6wU,5733
11
+ fastapi_voyager/web/graph-ui.js,sha256=wxKjmVEpaMJZXMTW7tJ4BiaACCI1oVN6cx7hSMI0K5U,6428
12
12
  fastapi_voyager/web/graphviz.svg.css,sha256=zDCjjpT0Idufu5YOiZI76PL70-avP3vTyzGPh9M85Do,1563
13
- fastapi_voyager/web/graphviz.svg.js,sha256=lvAdbjHc-lMSk4GQp-iqYA2PCFX4RKnW7dFaoe0LUHs,16005
14
- fastapi_voyager/web/index.html,sha256=C8gqka2omSHqx40C5_CCSMKHP-VJSPV3UFTrqQHGRtU,19635
13
+ fastapi_voyager/web/graphviz.svg.js,sha256=wZwz_lBztoXmujEN21P0w-HMpdmbqPwTQQ6Ebxd9rGo,18569
14
+ fastapi_voyager/web/index.html,sha256=3HixCgVF9VtTx89G3usDXpEh7NZnLk_p9siz4OUVUHE,17444
15
15
  fastapi_voyager/web/quasar.min.css,sha256=F5jQe7X2XT54VlvAaa2V3GsBFdVD-vxDZeaPLf6U9CU,203145
16
16
  fastapi_voyager/web/quasar.min.js,sha256=h0ftyPMW_CRiyzeVfQqiup0vrVt4_QWojpqmpnpn07E,502974
17
- fastapi_voyager/web/store.js,sha256=LPJdFxyFn8j7vOI41FKtWoB8agoqIUrR3tN5HRS_5e4,210
18
- fastapi_voyager/web/vue-main.js,sha256=qTPJ2CTT5T9kRR2h0DbroOGJVePRIF3e24u7JexqjPQ,13516
19
- fastapi_voyager/web/component/demo.js,sha256=FUwZqyMYjwf2J_YAzUBZ-gW9RFdOrz5zbxogBBYiYYE,347
17
+ fastapi_voyager/web/store.js,sha256=fW-3uUwWNUsW8vXbTqltHvvlIroBeZTJvFkMSjuWdVg,1630
18
+ fastapi_voyager/web/vue-main.js,sha256=H50LbB-g3jWaz3Xv2O8RgajlibjtoiHu1HDTumjf7sY,10766
19
+ fastapi_voyager/web/component/demo.js,sha256=bQb16Un4XZ3Mf8qL6gvyrXe_mmA3V3mSIRMQAWg2MNk,352
20
20
  fastapi_voyager/web/component/render-graph.js,sha256=e8Xgh2Kl-nYU0P1gstEmAepCgFnk2J6UdxW8TlMafGs,2322
21
21
  fastapi_voyager/web/component/route-code-display.js,sha256=8NJPPjNRUC21gjpY8XYEQs4RBbhX1pCiqEhJp39ku6k,3678
22
22
  fastapi_voyager/web/component/schema-code-display.js,sha256=qKUMV2RFQzR8deof2iC4vyp65UaWadtVsDAXjY-i3vE,7042
23
- fastapi_voyager/web/component/schema-field-filter.js,sha256=c--XiXJrhIS7sYo1x8ZwMoqak0k9xLkNYTWoli-zd38,6253
23
+ fastapi_voyager/web/component/schema-field-filter.js,sha256=i6Zp02wfSBWQb4AJ7H_Q9vgCVzLaVnH1I2JIot0sV-0,6172
24
24
  fastapi_voyager/web/icon/android-chrome-192x192.png,sha256=35sBy6jmUFJCcquStaafHH1qClZIbd-X3PIKSeLkrNo,37285
25
25
  fastapi_voyager/web/icon/android-chrome-512x512.png,sha256=eb2eDjCwIruc05029_0L9hcrkVkv8KceLn1DJMYU0zY,210789
26
26
  fastapi_voyager/web/icon/apple-touch-icon.png,sha256=gnWK46tPnvSw1-oYZjgI02wpoO4OrIzsVzGHC5oKWO0,33187
@@ -28,8 +28,8 @@ fastapi_voyager/web/icon/favicon-16x16.png,sha256=JC07jEzfIYxBIoQn_FHXvyHuxESdhW
28
28
  fastapi_voyager/web/icon/favicon-32x32.png,sha256=C7v1h58cfWOsiLp9yOIZtlx-dLasBcq3NqpHVGRmpt4,1859
29
29
  fastapi_voyager/web/icon/favicon.ico,sha256=tZolYIXkkBcFiYl1A8ksaXN2VjGamzcSdes838dLvNc,15406
30
30
  fastapi_voyager/web/icon/site.webmanifest,sha256=ep4Hzh9zhmiZF2At3Fp1dQrYQuYF_3ZPZxc1KcGBvwQ,263
31
- fastapi_voyager-0.12.4.dist-info/METADATA,sha256=9VUoRQ9sMRLqvukIAlC7kUi1Bcf2raXR9v9JRx7Ltbk,6523
32
- fastapi_voyager-0.12.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
33
- fastapi_voyager-0.12.4.dist-info/entry_points.txt,sha256=pEIKoUnIDXEtdMBq8EmXm70m16vELIu1VPz9-TBUFWM,53
34
- fastapi_voyager-0.12.4.dist-info/licenses/LICENSE,sha256=lNVRR3y_bFVoFKuK2JM8N4sFaj3m-7j29kvL3olFi5Y,1067
35
- fastapi_voyager-0.12.4.dist-info/RECORD,,
31
+ fastapi_voyager-0.12.6.dist-info/METADATA,sha256=sPfeuEuiQ4Wf_lOwdJL5BMTBIZXzT6Yk4zm175J_Pi4,6523
32
+ fastapi_voyager-0.12.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
33
+ fastapi_voyager-0.12.6.dist-info/entry_points.txt,sha256=pEIKoUnIDXEtdMBq8EmXm70m16vELIu1VPz9-TBUFWM,53
34
+ fastapi_voyager-0.12.6.dist-info/licenses/LICENSE,sha256=lNVRR3y_bFVoFKuK2JM8N4sFaj3m-7j29kvL3olFi5Y,1067
35
+ fastapi_voyager-0.12.6.dist-info/RECORD,,