@reventlessdev/reventless-core 3.0.0-alpha.238 → 3.0.0-alpha.240
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/CHANGELOG.md +40 -0
- package/package.json +12 -12
- package/src/Message.res +11 -11
- package/src/Message.res.mjs +15 -14
- package/src/Projection.res +2 -2
- package/src/Projection.res.mjs +5 -4
- package/src/adapter/Monitoring/Monitoring.res +24 -2
- package/src/adapter/Monitoring/Monitoring.res.mjs +3 -3
- package/src/admin/Platform_AdminApi.res.mjs +3 -3
- package/src/admin/Platform_Admin_Structure.res +33 -112
- package/src/admin/Platform_Admin_Structure.res.mjs +8 -138
- package/src/admin/Platform_ComponentDefinitionsApi.res +2 -1
- package/src/admin/Platform_ComponentDefinitionsApi.res.mjs +5 -1
- package/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry.res.mjs +12 -12
- package/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments.res.mjs +14 -14
- package/src/components/Aggregate/Aggregate_Callback.res +2 -2
- package/src/components/Aggregate/Aggregate_Callback.res.mjs +4 -4
- package/src/components/Api/ApiAllowedStatesHelpers.res.mjs +3 -3
- package/src/components/Api/ApiNoApiHelpers.res.mjs +5 -5
- package/src/components/Api/ApiTargetStateHelpers.res.mjs +3 -3
- package/src/components/Api/GraphQL_FragmentGenerator.res +140 -24
- package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +48 -21
- package/src/components/Api/GraphQL_SchemaInspector.res +1 -1
- package/src/components/Api/GraphQL_SchemaInspector.res.mjs +1 -1
- package/src/components/Api/MCP_SchemaGenerator.res +1 -1
- package/src/components/Api/MCP_SchemaGenerator.res.mjs +1 -1
- package/src/components/Api/SchemaType.res +6 -10
- package/src/components/Api/SchemaType.res.mjs +4 -4
- package/src/components/Api/StorageRefFields.res +1 -1
- package/src/components/Api/StorageRefFields.res.mjs +1 -1
- package/src/components/Api/SuryToJsonSchema.res +19 -0
- package/src/components/Api/SuryToJsonSchema.res.mjs +10 -5
- package/src/components/AutomationSlice/AutomationSlice_Callback.res +3 -4
- package/src/components/AutomationSlice/AutomationSlice_Callback.res.mjs +22 -23
- package/src/components/CommandTopic/CommandTopic_Callback.res +1 -2
- package/src/components/CommandTopic/CommandTopic_Callback.res.mjs +3 -4
- package/src/components/CommandTopic/CommandTopic_Helpers.res +1 -1
- package/src/components/CommandTopic/CommandTopic_Helpers.res.mjs +3 -3
- package/src/components/Counter/Counter.res.mjs +2 -2
- package/src/components/Counter/Counter_Callback.res.mjs +4 -4
- package/src/components/Counter/Counter_Operations.res.mjs +4 -4
- package/src/components/Dcb/Dcb_Builder.res +1 -1
- package/src/components/Dcb/Dcb_Builder.res.mjs +8 -6
- package/src/components/DcbEventLog/DcbEventLog_Builder.res.mjs +4 -3
- package/src/components/EventCollector/EventCollector_Builder.res +1 -1
- package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res +1 -2
- package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res.mjs +11 -12
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res +3 -4
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res.mjs +24 -25
- package/src/components/SideEffectHandler/SideEffectHandler_Callback.res +1 -1
- package/src/components/SideEffectHandler/SideEffectHandler_Callback.res.mjs +3 -3
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +2 -2
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res.mjs +4 -4
- package/src/components/StateViewSlice/StateViewSlice_Builder.res +1 -1
- package/src/components/StateViewSlice/StateViewSlice_Builder.res.mjs +3 -3
- package/src/plugin/api/PluginBaseFragment.res +12 -29
- package/src/plugin/api/PluginBaseFragment.res.mjs +3 -22
- package/src/plugin/component/Capability_Inference.res +118 -1
- package/src/plugin/component/Capability_Inference.res.mjs +128 -1
- package/src/plugin/component/Plugin_Builder.res +9 -2
- package/src/plugin/component/Plugin_Builder.res.mjs +5 -2
- package/src/plugin/component/Plugin_Helpers.res +11 -11
- package/src/plugin/component/Plugin_Helpers.res.mjs +11 -10
- package/src/plugin/component/Plugin_Structure.res +458 -296
- package/src/plugin/component/Plugin_Structure.res.mjs +259 -182
- package/src/plugin/component/Plugin_SubscriptionSchema.res +1 -1
- package/src/plugin/component/Plugin_SubscriptionSchema.res.mjs +1 -1
- package/src/plugin/component/SchemaWalker.res +11 -11
- package/src/plugin/component/SchemaWalker.res.mjs +8 -9
- package/src/plugin/connect/PluginExtensionPoint_Plugin.res.mjs +15 -15
- package/src/plugin/lifecycle/PluginBehavior.res.mjs +55 -55
- package/src/plugin/lifecycle/PluginSpec.res +22 -7
- package/src/plugin/lifecycle/PluginSpec.res.mjs +91 -36
- package/src/plugin/lifecycle/PluginsReadModelSpec.res +36 -9
- package/src/plugin/lifecycle/PluginsReadModelSpec.res.mjs +33 -22
- package/src/util/Interstack.res +3 -3
- package/src/util/LogFormat.res +1 -2
- package/src/util/LogFormat.res.mjs +2 -2
- package/tests/IdentityTest.res +6 -7
- package/tests/IdentityTest.res.mjs +7 -9
- package/tests/adapter/MonitoringTest.res +30 -3
- package/tests/adapter/MonitoringTest.res.mjs +31 -12
- package/tests/adapter/RuntimeExtensionHookReachTest.res +0 -1
- package/tests/adapter/RuntimeExtensionHookReachTest.res.mjs +5 -7
- package/tests/admin/Platform_Admin_StructureTest.res +254 -0
- package/tests/admin/Platform_Admin_StructureTest.res.mjs +219 -0
- package/tests/admin/Platform_BakedManifestTest.res +1 -0
- package/tests/admin/Platform_BakedManifestTest.res.mjs +1 -0
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res +3 -0
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res.mjs +6 -0
- package/tests/admin/Platform_PluginStructuresApiTest.res +1 -0
- package/tests/admin/Platform_PluginStructuresApiTest.res.mjs +2 -0
- package/tests/aggregate/AggregateCacheTest.res +0 -1
- package/tests/aggregate/AggregateCacheTest.res.mjs +13 -15
- package/tests/aggregate/AggregateConflictTest.res +0 -1
- package/tests/aggregate/AggregateConflictTest.res.mjs +7 -9
- package/tests/aggregate/AggregateFixtures.res +0 -1
- package/tests/aggregate/AggregateFixtures.res.mjs +19 -21
- package/tests/aggregate/AggregateSnapshotTest.res +1 -2
- package/tests/aggregate/AggregateSnapshotTest.res.mjs +15 -16
- package/tests/api/ApiNoApiTest.res.mjs +17 -9
- package/tests/api/GraphQL_FragmentGeneratorTest.res +232 -0
- package/tests/api/GraphQL_FragmentGeneratorTest.res.mjs +207 -55
- package/tests/api/PsInternalFieldsReadModel.res +21 -0
- package/tests/api/PsInternalFieldsReadModel.res.mjs +74 -0
- package/tests/api/StorageRefFieldsTest.res.mjs +13 -13
- package/tests/api/SuryToJsonSchemaTest.res +73 -3
- package/tests/api/SuryToJsonSchemaTest.res.mjs +364 -816
- package/tests/commandgenerator/CommandGeneratorFixtures.res +0 -1
- package/tests/commandgenerator/CommandGeneratorFixtures.res.mjs +19 -21
- package/tests/commandgenerator/OwnerStampingTest.res +0 -1
- package/tests/commandgenerator/OwnerStampingTest.res.mjs +9 -11
- package/tests/commandtopic/CommandTopicCallbackFixtures.res +0 -1
- package/tests/commandtopic/CommandTopicCallbackFixtures.res.mjs +7 -9
- package/tests/counter/CounterFixtures.res +0 -1
- package/tests/counter/CounterFixtures.res.mjs +1 -4
- package/tests/dcb/DcbDecodeTest.res.mjs +24 -24
- package/tests/dcb/DcbEventLogOperationsTest.res +2 -2
- package/tests/dcb/DcbEventLogOperationsTest.res.mjs +3 -3
- package/tests/dcb/DcbEventLogSchemaTest.res.mjs +7 -7
- package/tests/dcb/DcbFixtures.res +0 -1
- package/tests/dcb/DcbFixtures.res.mjs +87 -89
- package/tests/dcb/DcbTagTest.res.mjs +6 -6
- package/tests/dcb/DcbValidationTest.res.mjs +52 -52
- package/tests/eventlog/EventLogFixtures.res +0 -1
- package/tests/eventlog/EventLogFixtures.res.mjs +7 -9
- package/tests/eventmapper/EventMapperFixtures.res +0 -1
- package/tests/eventmapper/EventMapperFixtures.res.mjs +24 -26
- package/tests/eventtopic/EventTopicFixtures.res +0 -1
- package/tests/eventtopic/EventTopicFixtures.res.mjs +7 -9
- package/tests/extensionpoint/ExtensionPointFixtures.res +0 -1
- package/tests/extensionpoint/ExtensionPointFixtures.res.mjs +10 -12
- package/tests/extensionpoint/ExtensionPointOperationsTest.res +1 -2
- package/tests/extensionpoint/ExtensionPointOperationsTest.res.mjs +9 -10
- package/tests/logger/LogFormatTest.res +3 -2
- package/tests/logger/LogFormatTest.res.mjs +7 -9
- package/tests/message/MessageTest.res +2 -2
- package/tests/message/MessageTest.res.mjs +8 -7
- package/tests/message/MetaEnvelopeTest.res +5 -5
- package/tests/message/MetaEnvelopeTest.res.mjs +12 -11
- package/tests/plugin/ManifestVisibilityTest.res.mjs +7 -7
- package/tests/plugin/PluginDefinitionScalars.res +5 -3
- package/tests/plugin/PluginDefinitionScalars.res.mjs +2 -2
- package/tests/plugin/PluginLifecycleCorpusTest.res +4 -3
- package/tests/plugin/PluginLifecycleCorpusTest.res.mjs +3 -6
- package/tests/plugin/PluginSpecExperiment.res +0 -1
- package/tests/plugin/PluginSpecExperiment.res.mjs +12 -14
- package/tests/plugin/PluginStructureTest.res +292 -2
- package/tests/plugin/PluginStructureTest.res.mjs +391 -88
- package/tests/plugin/Plugin_EventQuerySchemaTest.res.mjs +3 -3
- package/tests/plugin/SchemaWalkerTest.res +0 -1
- package/tests/plugin/SchemaWalkerTest.res.mjs +17 -19
- package/tests/plugin/StateChangeSlice/PsAttachInvoice.res.mjs +5 -5
- package/tests/plugin/StateChangeSlice/PsChangePhoto.res.mjs +8 -8
- package/tests/plugin/StateChangeSlice/PsDispatchShipment.res.mjs +5 -5
- package/tests/plugin/StateChangeSlice/PsGatedCommands.res.mjs +9 -9
- package/tests/plugin/StateChangeSlice/PsPlaceOrder.res.mjs +5 -5
- package/tests/plugin/StateChangeSlice/PsReserveStock.res.mjs +8 -8
- package/tests/plugin/StateChangeSlice/PsShipOrder.res.mjs +15 -15
- package/tests/plugin/StateChangeSlice/PsTypoStore.res +31 -0
- package/tests/plugin/StateChangeSlice/PsTypoStore.res.mjs +62 -0
- package/tests/plugin/StateChangeSlice/PsUploadAvatar.res.mjs +8 -8
- package/tests/plugin/StateChangeSlice/PsUploadImages.res +40 -0
- package/tests/plugin/StateChangeSlice/PsUploadImages.res.mjs +66 -0
- package/tests/plugin/StateViewSlice/PsAnnotatedView.res.mjs +13 -12
- package/tests/plugin/StateViewSlice/PsAvailableProductsView.res.mjs +8 -8
- package/tests/plugin/StateViewSlice/PsCategoriesView.res.mjs +6 -6
- package/tests/plugin/StateViewSlice/PsCustomersView.res.mjs +10 -10
- package/tests/plugin/StateViewSlice/PsGatedView.res.mjs +6 -6
- package/tests/plugin/StateViewSlice/PsOrdersView.res.mjs +9 -9
- package/tests/plugin/StateViewSlice/PsShipmentsView.res.mjs +11 -10
- package/tests/plugin/pluginDefinitionRequiredScalars.txt +15 -0
- package/tests/querydb/QueryDbFixtures.res +0 -1
- package/tests/querydb/QueryDbFixtures.res.mjs +5 -7
- package/tests/sideeffecthandler/SideEffectHandlerFixtures.res +0 -1
- package/tests/sideeffecthandler/SideEffectHandlerFixtures.res.mjs +4 -6
- package/tests/util/CommandPublisherTest.res +0 -1
- package/tests/util/CommandPublisherTest.res.mjs +4 -6
|
@@ -132,6 +132,21 @@ let deriveObjectTypeWithNested = (
|
|
|
132
132
|
): array<string> =>
|
|
133
133
|
switch SchemaType.fromSuryObject(~typeName, schema) {
|
|
134
134
|
| Some(fields) =>
|
|
135
|
+
// `@internal` joins the caller's exclusions rather than replacing them. The
|
|
136
|
+
// caller's list is a decision made where the query entry is assembled; this
|
|
137
|
+
// one is a declaration on the field itself, and the schema is the better
|
|
138
|
+
// place for it — a hand-written list has to be kept in step with the record
|
|
139
|
+
// by whoever next edits it, which is the drift that made a hand-maintained
|
|
140
|
+
// `pluginExcludeFields` necessary in the first place.
|
|
141
|
+
//
|
|
142
|
+
// This is the single point for the SDL: every generated object type is
|
|
143
|
+
// derived here, so a field declared internal is absent from all of them
|
|
144
|
+
// without any entry having to say so.
|
|
145
|
+
let declaredInternal =
|
|
146
|
+
Reventless.StateAnnotations.getSpec(schema)
|
|
147
|
+
->Option.flatMap(spec => spec.internal)
|
|
148
|
+
->Option.getOr([])
|
|
149
|
+
let excludeFields = Array.concat(excludeFields, declaredInternal)
|
|
135
150
|
let filteredFields = if excludeFields->Array.length > 0 {
|
|
136
151
|
let d = Dict.make()
|
|
137
152
|
fields
|
|
@@ -411,9 +426,16 @@ let deriveObjectQueryField = (
|
|
|
411
426
|
~subIdField: option<string>=?,
|
|
412
427
|
): string =>
|
|
413
428
|
if includeIdParam {
|
|
429
|
+
// `includeRetired` reaches this door for the reason it reaches the list: a
|
|
430
|
+
// caller the server would serve a retired row to had, until it did, no way
|
|
431
|
+
// to ask for one *singly*. The archive toggle put such rows on screen and
|
|
432
|
+
// clicking one read a door that refuses them to everybody — `decideRetired`
|
|
433
|
+
// withholds from `Elevated` and `System` too until they ask, and here there
|
|
434
|
+
// was nothing to ask with.
|
|
414
435
|
switch subIdField {
|
|
415
|
-
| Some(sortField) =>
|
|
416
|
-
|
|
436
|
+
| Some(sortField) =>
|
|
437
|
+
` ${singleFieldName}(id: ID!, ${sortField}: String!, includeRetired: Boolean): ${typeName}`
|
|
438
|
+
| None => ` ${singleFieldName}(id: ID!, includeRetired: Boolean): ${typeName}`
|
|
417
439
|
}
|
|
418
440
|
} else {
|
|
419
441
|
` ${singleFieldName}: ${typeName}`
|
|
@@ -434,7 +456,38 @@ let deriveByIdsQueryField = (
|
|
|
434
456
|
~listFieldName: string,
|
|
435
457
|
~returnTypeName: string,
|
|
436
458
|
): string =>
|
|
437
|
-
` ${listFieldName}ByIds(ids: [String!]
|
|
459
|
+
` ${listFieldName}ByIds(ids: [String!]!, includeRetired: Boolean): [${returnTypeName}!]!`
|
|
460
|
+
|
|
461
|
+
// ── The reference door ─────────────────────────────────────────────────────
|
|
462
|
+
//
|
|
463
|
+
// What a caller holding a pointer to a row may learn about it: its id, the label
|
|
464
|
+
// a reference resolves to, and — where the view declares a retirement — whether
|
|
465
|
+
// this row is in one and which state that is.
|
|
466
|
+
//
|
|
467
|
+
// The narrowness is the *type's*, which is the whole reason this is a separate
|
|
468
|
+
// field rather than an argument on the by-ids door. A rule that answered a
|
|
469
|
+
// retired row on the existing door "as long as only the safe fields were asked
|
|
470
|
+
// for" would have to be re-implemented, identically, in four backends and to
|
|
471
|
+
// survive aliases, fragments and `__typename`. Here a caller cannot ask for a
|
|
472
|
+
// price, because the type has no price.
|
|
473
|
+
//
|
|
474
|
+
// Emitted for every view, not only for the ones that opted in, on exactly the
|
|
475
|
+
// reasoning `includeRetired` states above: a field that appears and disappears
|
|
476
|
+
// with an annotation makes adding or removing that annotation a breaking schema
|
|
477
|
+
// change, and forces every client to feature-detect. What the annotation decides
|
|
478
|
+
// is not whether the door exists but whether a *retired* row comes through it —
|
|
479
|
+
// without it this is a cheap label read that narrows exactly as every other door
|
|
480
|
+
// does.
|
|
481
|
+
let deriveRefTypeSdl = (~returnTypeName: string): string =>
|
|
482
|
+
`type ${returnTypeName}Ref {\n id: ID!\n label: String!\n retired: Boolean!\n retiredState: String\n}`
|
|
483
|
+
|
|
484
|
+
// `retiredState` is null in two cases that do not need telling apart by a
|
|
485
|
+
// consumer: a live row, and a boolean-form retirement, where the field is the
|
|
486
|
+
// state and `retired: true` has already said everything there is to say.
|
|
487
|
+
let deriveRefsQueryField = (
|
|
488
|
+
~listFieldName: string,
|
|
489
|
+
~returnTypeName: string,
|
|
490
|
+
): string => ` ${listFieldName}Refs(ids: [ID!]!): [${returnTypeName}Ref!]!`
|
|
438
491
|
|
|
439
492
|
// `includeRetired` sits beside the paging arguments rather than inside `filter`,
|
|
440
493
|
// and that placement is the point. `filter` is the caller's description of the
|
|
@@ -459,6 +512,63 @@ let deriveConnectionQueryField = (
|
|
|
459
512
|
` ${listFieldName}(filter: ${filterTypeName}${orderByArg}, first: Int, after: String, last: Int, before: String, includeRetired: Boolean): ${singularTypeName}Connection!`
|
|
460
513
|
}
|
|
461
514
|
|
|
515
|
+
// ── The by-index door ──────────────────────────────────────────────────────
|
|
516
|
+
//
|
|
517
|
+
// One derivation, called by every backend that serves this field, because the
|
|
518
|
+
// alternative was tried and did not survive contact. The field used to be
|
|
519
|
+
// emitted here for AppSync and again, independently, in the local adapter, and
|
|
520
|
+
// the two agreed on neither its name, its argument nor its return type. Both
|
|
521
|
+
// were wrong in the same way: each disagreed with the resolver standing behind
|
|
522
|
+
// it. The AppSync shape declared `id: ID!` while its resolver read the index
|
|
523
|
+
// field, so the value could not be passed at all; the local shape promised
|
|
524
|
+
// `[String]` while its resolver returned whole rows, so every call failed to
|
|
525
|
+
// serialise. A door that answers on no backend is a door whose signature can be
|
|
526
|
+
// chosen on the merits, which is what the one below is.
|
|
527
|
+
|
|
528
|
+
/** The row field an index is keyed on.
|
|
529
|
+
|
|
530
|
+
For a named index (`@index("byOwner") ownerId`) the index name and the field it
|
|
531
|
+
indexes differ, and it is the *field* every resolver filters on; for an unnamed
|
|
532
|
+
index the two are the same string. */
|
|
533
|
+
let indexKeyField = (indexConfig: Reventless.ReadModel.indexConfig): string =>
|
|
534
|
+
indexConfig.idField->Option.getOr(indexConfig.index)
|
|
535
|
+
|
|
536
|
+
/** `<single>By<Index>`, dropping a leading `by` from the index name so
|
|
537
|
+
`@index("byOwner")` reads `XByOwner` rather than `XByByOwner`. */
|
|
538
|
+
let indexQueryFieldName = (~singleFieldName: string, ~index: string): string => {
|
|
539
|
+
let stripped = if index->String.startsWith("by") && index->String.length > 2 {
|
|
540
|
+
index->String.slice(~start=2, ~end=index->String.length)
|
|
541
|
+
} else {
|
|
542
|
+
index
|
|
543
|
+
}
|
|
544
|
+
singleFieldName ++ "By" ++ stripped->String.capitalize
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/** The by-index door's signature.
|
|
548
|
+
|
|
549
|
+
Paging and `includeRetired` are here for the reasons `deriveConnectionQueryField`
|
|
550
|
+
gives above — this door reads a secondary index that can carry as many rows as
|
|
551
|
+
the list, and an elevated caller that can widen every other door but this one
|
|
552
|
+
would find the archive reachable by id and by list and not by the index that
|
|
553
|
+
exists to look rows up. */
|
|
554
|
+
let deriveIndexQueryField = (
|
|
555
|
+
~singleFieldName: string,
|
|
556
|
+
~indexConfig: Reventless.ReadModel.indexConfig,
|
|
557
|
+
~connectionTypeName: string,
|
|
558
|
+
): string => {
|
|
559
|
+
let fieldName = indexQueryFieldName(~singleFieldName, ~index=indexConfig.index)
|
|
560
|
+
let keyField = indexKeyField(indexConfig)
|
|
561
|
+
// An index with a sort key can be narrowed to one exact value on it. Optional,
|
|
562
|
+
// unlike the partition argument: naming the index value is what the door is
|
|
563
|
+
// for, narrowing further is a refinement. The AppSync sort template has read
|
|
564
|
+
// this argument all along, against an SDL that never offered it.
|
|
565
|
+
let sortArg = switch indexConfig.subIdField {
|
|
566
|
+
| Some(sortField) => `${sortField}: String, `
|
|
567
|
+
| None => ""
|
|
568
|
+
}
|
|
569
|
+
` ${fieldName}(${keyField}: String!, ${sortArg}first: Int, after: String, last: Int, before: String, includeRetired: Boolean): ${connectionTypeName}!`
|
|
570
|
+
}
|
|
571
|
+
|
|
462
572
|
// ── Mutation field derivation ──────────────────────────────────────────────
|
|
463
573
|
|
|
464
574
|
let deriveMutationFieldFromObject = (
|
|
@@ -546,7 +656,7 @@ let generate = (
|
|
|
546
656
|
// schema shape — see `mutationSchemaEntry.injectIdArg`.
|
|
547
657
|
let injectIdArg = entry.injectIdArg->Option.getOr(true)
|
|
548
658
|
switch schema {
|
|
549
|
-
|
|
|
659
|
+
| AnyOf({anyOf}) =>
|
|
550
660
|
// Map each fieldName to its variant in anyOf by matching the constructor
|
|
551
661
|
// name. Position-based pairing (anyOf index ↔ fieldNames index) breaks
|
|
552
662
|
// when `@noApi` filters out some variants but the schema still carries
|
|
@@ -555,17 +665,8 @@ let generate = (
|
|
|
555
665
|
// index 1, leaking a stale `_0: Platform_Plugin_Deactivate_0` arg.
|
|
556
666
|
let variantNames = anyOf->Array.map(v =>
|
|
557
667
|
switch v {
|
|
558
|
-
| Object({
|
|
559
|
-
|
|
560
|
-
->Array.find(item => item.location == "TAG")
|
|
561
|
-
->Option.flatMap(item =>
|
|
562
|
-
switch item.schema {
|
|
563
|
-
| String({const}) => Some(const)
|
|
564
|
-
| _ => None
|
|
565
|
-
}
|
|
566
|
-
)
|
|
567
|
-
->Option.getOr("")
|
|
568
|
-
| String({const}) => const
|
|
668
|
+
| Object({properties}) => SchemaWalker.tagConstOf(properties)->Option.getOr("")
|
|
669
|
+
| String({const: ?Some(const)}) => const
|
|
569
670
|
| _ => ""
|
|
570
671
|
}
|
|
571
672
|
)
|
|
@@ -652,6 +753,23 @@ let generate = (
|
|
|
652
753
|
~returnTypeName=entry.returnTypeName,
|
|
653
754
|
),
|
|
654
755
|
)
|
|
756
|
+
|
|
757
|
+
// The reference door, under the by-ids condition because it is the same
|
|
758
|
+
// read. Emitted here rather than per-backend so the field a backend
|
|
759
|
+
// provisions a resolver for is one this SDL declares: the AppSync adapter
|
|
760
|
+
// registers `<list>Refs` for every queryable on exactly that premise, and
|
|
761
|
+
// a door named in one half and not the other fails the deploy outright.
|
|
762
|
+
let refTypeName = entry.returnTypeName ++ "Ref"
|
|
763
|
+
if !(seenTypes->Set.has(refTypeName)) {
|
|
764
|
+
seenTypes->Set.add(refTypeName)
|
|
765
|
+
types->Array.push(deriveRefTypeSdl(~returnTypeName=entry.returnTypeName))
|
|
766
|
+
}
|
|
767
|
+
queries->Array.push(
|
|
768
|
+
deriveRefsQueryField(
|
|
769
|
+
~listFieldName=entry.listFieldName,
|
|
770
|
+
~returnTypeName=entry.returnTypeName,
|
|
771
|
+
),
|
|
772
|
+
)
|
|
655
773
|
}
|
|
656
774
|
|
|
657
775
|
let listFieldName = entry.listFieldName
|
|
@@ -677,17 +795,15 @@ let generate = (
|
|
|
677
795
|
switch entry.indexQueries {
|
|
678
796
|
| Some(indexes) =>
|
|
679
797
|
let connectionTypeName = entry.returnTypeName ++ "Connection"
|
|
680
|
-
indexes->Array.forEach(
|
|
681
|
-
let stripped = if index->String.startsWith("by") && index->String.length > 2 {
|
|
682
|
-
index->String.slice(~start=2, ~end=index->String.length)
|
|
683
|
-
} else {
|
|
684
|
-
index
|
|
685
|
-
}
|
|
686
|
-
let fieldName = entry.singleFieldName ++ "By" ++ stripped->String.capitalize
|
|
798
|
+
indexes->Array.forEach(indexConfig =>
|
|
687
799
|
queries->Array.push(
|
|
688
|
-
|
|
800
|
+
deriveIndexQueryField(
|
|
801
|
+
~singleFieldName=entry.singleFieldName,
|
|
802
|
+
~indexConfig,
|
|
803
|
+
~connectionTypeName,
|
|
804
|
+
),
|
|
689
805
|
)
|
|
690
|
-
|
|
806
|
+
)
|
|
691
807
|
| None => ()
|
|
692
808
|
}
|
|
693
809
|
|
|
@@ -5,6 +5,7 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
|
5
5
|
import * as Stdlib_String from "@rescript/runtime/lib/es6/Stdlib_String.js";
|
|
6
6
|
import * as Api_Naming$ReventlessCore from "./Api_Naming.res.mjs";
|
|
7
7
|
import * as SchemaType$ReventlessCore from "./SchemaType.res.mjs";
|
|
8
|
+
import * as SchemaWalker$ReventlessCore from "../../plugin/component/SchemaWalker.res.mjs";
|
|
8
9
|
import * as StateAnnotations$Reventless from "@reventlessdev/reventless-spec/src/components/StateAnnotations.res.mjs";
|
|
9
10
|
import * as GraphQL_Stitcher$ReventlessCore from "./GraphQL_Stitcher.res.mjs";
|
|
10
11
|
|
|
@@ -116,12 +117,14 @@ function deriveObjectTypeWithNested(typeName, excludeFieldsOpt, includeIdParamOp
|
|
|
116
117
|
if (fields === undefined) {
|
|
117
118
|
return [];
|
|
118
119
|
}
|
|
120
|
+
let declaredInternal = Stdlib_Option.getOr(Stdlib_Option.flatMap(StateAnnotations$Reventless.getSpec(schema), spec => spec.internal), []);
|
|
121
|
+
let excludeFields$1 = excludeFields.concat(declaredInternal);
|
|
119
122
|
let filteredFields;
|
|
120
|
-
if (excludeFields.length !== 0) {
|
|
123
|
+
if (excludeFields$1.length !== 0) {
|
|
121
124
|
let d = {};
|
|
122
125
|
Object.entries(fields).forEach(param => {
|
|
123
126
|
let k = param[0];
|
|
124
|
-
if (!excludeFields.some(ex => ex === k)) {
|
|
127
|
+
if (!excludeFields$1.some(ex => ex === k)) {
|
|
125
128
|
d[k] = param[1];
|
|
126
129
|
return;
|
|
127
130
|
}
|
|
@@ -354,9 +357,9 @@ function deriveObjectQueryField(singleFieldName, typeName, includeIdParamOpt, su
|
|
|
354
357
|
let includeIdParam = includeIdParamOpt !== undefined ? includeIdParamOpt : true;
|
|
355
358
|
if (includeIdParam) {
|
|
356
359
|
if (subIdField !== undefined) {
|
|
357
|
-
return ` ` + singleFieldName + `(id: ID!, ` + subIdField + `: String
|
|
360
|
+
return ` ` + singleFieldName + `(id: ID!, ` + subIdField + `: String!, includeRetired: Boolean): ` + typeName;
|
|
358
361
|
} else {
|
|
359
|
-
return ` ` + singleFieldName + `(id: ID
|
|
362
|
+
return ` ` + singleFieldName + `(id: ID!, includeRetired: Boolean): ` + typeName;
|
|
360
363
|
}
|
|
361
364
|
} else {
|
|
362
365
|
return ` ` + singleFieldName + `: ` + typeName;
|
|
@@ -368,7 +371,15 @@ function deriveListQueryField(listFieldName, pluralTypeName) {
|
|
|
368
371
|
}
|
|
369
372
|
|
|
370
373
|
function deriveByIdsQueryField(listFieldName, returnTypeName) {
|
|
371
|
-
return ` ` + listFieldName + `ByIds(ids: [String!]
|
|
374
|
+
return ` ` + listFieldName + `ByIds(ids: [String!]!, includeRetired: Boolean): [` + returnTypeName + `!]!`;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function deriveRefTypeSdl(returnTypeName) {
|
|
378
|
+
return `type ` + returnTypeName + `Ref {\n id: ID!\n label: String!\n retired: Boolean!\n retiredState: String\n}`;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function deriveRefsQueryField(listFieldName, returnTypeName) {
|
|
382
|
+
return ` ` + listFieldName + `Refs(ids: [ID!]!): [` + returnTypeName + `Ref!]!`;
|
|
372
383
|
}
|
|
373
384
|
|
|
374
385
|
function deriveConnectionQueryField(listFieldName, singularTypeName, filterTypeName, hasOrderByOpt) {
|
|
@@ -377,6 +388,23 @@ function deriveConnectionQueryField(listFieldName, singularTypeName, filterTypeN
|
|
|
377
388
|
return ` ` + listFieldName + `(filter: ` + filterTypeName + orderByArg + `, first: Int, after: String, last: Int, before: String, includeRetired: Boolean): ` + singularTypeName + `Connection!`;
|
|
378
389
|
}
|
|
379
390
|
|
|
391
|
+
function indexKeyField(indexConfig) {
|
|
392
|
+
return Stdlib_Option.getOr(indexConfig.idField, indexConfig.index);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function indexQueryFieldName(singleFieldName, index) {
|
|
396
|
+
let stripped = index.startsWith("by") && index.length > 2 ? index.slice(2, index.length) : index;
|
|
397
|
+
return singleFieldName + "By" + Stdlib_String.capitalize(stripped);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function deriveIndexQueryField(singleFieldName, indexConfig, connectionTypeName) {
|
|
401
|
+
let fieldName = indexQueryFieldName(singleFieldName, indexConfig.index);
|
|
402
|
+
let keyField = indexKeyField(indexConfig);
|
|
403
|
+
let sortField = indexConfig.subIdField;
|
|
404
|
+
let sortArg = sortField !== undefined ? sortField + `: String, ` : "";
|
|
405
|
+
return ` ` + fieldName + `(` + keyField + `: String!, ` + sortArg + `first: Int, after: String, last: Int, before: String, includeRetired: Boolean): ` + connectionTypeName + `!`;
|
|
406
|
+
}
|
|
407
|
+
|
|
380
408
|
function deriveMutationFieldFromObject(fieldName, collectedTypes, seenTypes, variantSchema) {
|
|
381
409
|
let fields = SchemaType$ReventlessCore.fromSuryObject(fieldName, variantSchema);
|
|
382
410
|
if (fields === undefined) {
|
|
@@ -419,7 +447,7 @@ function generate(mutationEntries, queryEntries) {
|
|
|
419
447
|
} else {
|
|
420
448
|
return;
|
|
421
449
|
}
|
|
422
|
-
case "
|
|
450
|
+
case "anyOf" :
|
|
423
451
|
let anyOf = schema.anyOf;
|
|
424
452
|
let variantNames = anyOf.map(v => {
|
|
425
453
|
switch (v.type) {
|
|
@@ -431,16 +459,7 @@ function generate(mutationEntries, queryEntries) {
|
|
|
431
459
|
return "";
|
|
432
460
|
}
|
|
433
461
|
case "object" :
|
|
434
|
-
return Stdlib_Option.getOr(
|
|
435
|
-
let match = item.schema;
|
|
436
|
-
if (match.type !== "string") {
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
let $$const = match.const;
|
|
440
|
-
if ($$const !== undefined) {
|
|
441
|
-
return $$const;
|
|
442
|
-
}
|
|
443
|
-
}), "");
|
|
462
|
+
return Stdlib_Option.getOr(SchemaWalker$ReventlessCore.tagConstOf(v.properties), "");
|
|
444
463
|
default:
|
|
445
464
|
return "";
|
|
446
465
|
}
|
|
@@ -481,6 +500,12 @@ function generate(mutationEntries, queryEntries) {
|
|
|
481
500
|
queries.push(singleField);
|
|
482
501
|
if (includeIdParam && entry.subIdField === undefined) {
|
|
483
502
|
queries.push(deriveByIdsQueryField(entry.listFieldName, entry.returnTypeName));
|
|
503
|
+
let refTypeName = entry.returnTypeName + "Ref";
|
|
504
|
+
if (!seenTypes.has(refTypeName)) {
|
|
505
|
+
seenTypes.add(refTypeName);
|
|
506
|
+
types.push(deriveRefTypeSdl(entry.returnTypeName));
|
|
507
|
+
}
|
|
508
|
+
queries.push(deriveRefsQueryField(entry.listFieldName, entry.returnTypeName));
|
|
484
509
|
}
|
|
485
510
|
let listFieldName = entry.listFieldName;
|
|
486
511
|
let _sf = entry.subIdField;
|
|
@@ -495,11 +520,8 @@ function generate(mutationEntries, queryEntries) {
|
|
|
495
520
|
let indexes = entry.indexQueries;
|
|
496
521
|
if (indexes !== undefined) {
|
|
497
522
|
let connectionTypeName = entry.returnTypeName + "Connection";
|
|
498
|
-
indexes.forEach(
|
|
499
|
-
|
|
500
|
-
let stripped = index.startsWith("by") && index.length > 2 ? index.slice(2, index.length) : index;
|
|
501
|
-
let fieldName = entry.singleFieldName + "By" + Stdlib_String.capitalize(stripped);
|
|
502
|
-
queries.push(` ` + fieldName + `(id: ID!, first: Int, after: String, last: Int, before: String): ` + connectionTypeName + `!`);
|
|
523
|
+
indexes.forEach(indexConfig => {
|
|
524
|
+
queries.push(deriveIndexQueryField(entry.singleFieldName, indexConfig, connectionTypeName));
|
|
503
525
|
});
|
|
504
526
|
}
|
|
505
527
|
if (connectionSpec) {
|
|
@@ -579,7 +601,12 @@ export {
|
|
|
579
601
|
deriveObjectQueryField,
|
|
580
602
|
deriveListQueryField,
|
|
581
603
|
deriveByIdsQueryField,
|
|
604
|
+
deriveRefTypeSdl,
|
|
605
|
+
deriveRefsQueryField,
|
|
582
606
|
deriveConnectionQueryField,
|
|
607
|
+
indexKeyField,
|
|
608
|
+
indexQueryFieldName,
|
|
609
|
+
deriveIndexQueryField,
|
|
583
610
|
deriveMutationFieldFromObject,
|
|
584
611
|
mutationArgTypes,
|
|
585
612
|
generate,
|
|
@@ -29,7 +29,7 @@ let inspectMutationFields = (~fieldPrefix: string, commandSchema: S.t<'a>): arra
|
|
|
29
29
|
let collectedTypes: array<string> = []
|
|
30
30
|
let seenTypes = Set.make()
|
|
31
31
|
switch schema {
|
|
32
|
-
|
|
|
32
|
+
| AnyOf({anyOf}) =>
|
|
33
33
|
let constructorNames = Reventless.DcbTag.extractAllVariantNames(commandSchema)
|
|
34
34
|
anyOf->Array.forEachWithIndex((variantSchema, i) => {
|
|
35
35
|
let fieldName = switch constructorNames->Array.get(i) {
|
|
@@ -27,7 +27,7 @@ function inspectMutationFields(fieldPrefix, commandSchema) {
|
|
|
27
27
|
fields.push(field);
|
|
28
28
|
});
|
|
29
29
|
break;
|
|
30
|
-
case "
|
|
30
|
+
case "anyOf" :
|
|
31
31
|
let constructorNames = DcbTag$Reventless.extractAllVariantNames(commandSchema);
|
|
32
32
|
commandSchema.anyOf.forEach((variantSchema, i) => {
|
|
33
33
|
let name = constructorNames[i];
|
|
@@ -52,7 +52,7 @@ let generateTools = (
|
|
|
52
52
|
let entryDescription = entry.description->Option.getOr("")
|
|
53
53
|
|
|
54
54
|
switch schema {
|
|
55
|
-
|
|
|
55
|
+
| AnyOf({anyOf}) =>
|
|
56
56
|
// Aggregate commands: each variant is a separate tool.
|
|
57
57
|
// Inject an "id" property (aggregate instance ID) since aggregate
|
|
58
58
|
// commands target a specific instance.
|
|
@@ -33,7 +33,7 @@ function generateTools(pluginName, mutationEntries) {
|
|
|
33
33
|
inputSchema: inputSchema
|
|
34
34
|
});
|
|
35
35
|
return;
|
|
36
|
-
case "
|
|
36
|
+
case "anyOf" :
|
|
37
37
|
schema.anyOf.forEach((variantSchema, i) => {
|
|
38
38
|
let fieldName = Stdlib_Option.getOr(entry.fieldNames[i], "");
|
|
39
39
|
if (fieldName.length <= 0) {
|
|
@@ -99,15 +99,11 @@ and shapeOf = (~parentName: string, ~fieldName: string, schema: S.t<unknown>): s
|
|
|
99
99
|
| BigInt(_) => ScalarBigInt
|
|
100
100
|
| Array({items, additionalItems}) =>
|
|
101
101
|
let itemType = switch items->Array.get(0) {
|
|
102
|
-
| Some(
|
|
103
|
-
fromSury(
|
|
104
|
-
~parentName,
|
|
105
|
-
~fieldName,
|
|
106
|
-
itemSchema->(Obj.magic: S.t<unknown> => S.t<unknown>),
|
|
107
|
-
)
|
|
102
|
+
| Some(itemSchema) => fromSury(~parentName, ~fieldName, itemSchema)
|
|
108
103
|
| None =>
|
|
109
|
-
// sury stores the
|
|
110
|
-
// additionalItems
|
|
104
|
+
// For a homogeneous S.array() sury stores the element schema in
|
|
105
|
+
// additionalItems (items holds fixed tuple positions). additionalItems is
|
|
106
|
+
// @unboxed: Strip="strip" | Strict="strict" | Schema(t) = the schema object.
|
|
111
107
|
switch additionalItems {
|
|
112
108
|
| Schema(s) => fromSury(~parentName, ~fieldName, s)
|
|
113
109
|
| _ => ScalarString
|
|
@@ -135,7 +131,7 @@ and shapeOf = (~parentName: string, ~fieldName: string, schema: S.t<unknown>): s
|
|
|
135
131
|
} else {
|
|
136
132
|
ObjectRef(nestedName, fields)
|
|
137
133
|
}
|
|
138
|
-
|
|
|
134
|
+
| AnyOf({anyOf}) =>
|
|
139
135
|
let nonNullVariants = anyOf->Array.filter(v =>
|
|
140
136
|
switch v {
|
|
141
137
|
| Null(_) | Undefined(_) => false
|
|
@@ -196,7 +192,7 @@ let optionalFieldNames = (schema: S.t<unknown>): array<string> =>
|
|
|
196
192
|
->Dict.toArray
|
|
197
193
|
->Array.filterMap(((propName, propSchema)) =>
|
|
198
194
|
switch propSchema {
|
|
199
|
-
|
|
|
195
|
+
| AnyOf({anyOf}) =>
|
|
200
196
|
anyOf->Array.some(v =>
|
|
201
197
|
switch v {
|
|
202
198
|
| Null(_) | Undefined(_) => true
|
|
@@ -92,8 +92,8 @@ function shapeOf(parentName, fieldName, schema) {
|
|
|
92
92
|
};
|
|
93
93
|
case "array" :
|
|
94
94
|
let additionalItems = schema.additionalItems;
|
|
95
|
-
let
|
|
96
|
-
let itemType =
|
|
95
|
+
let itemSchema = schema.items[0];
|
|
96
|
+
let itemType = itemSchema !== undefined ? fromSury(parentName, fieldName, itemSchema) : (
|
|
97
97
|
additionalItems === "strip" || additionalItems === "strict" ? "ScalarString" : fromSury(parentName, fieldName, additionalItems)
|
|
98
98
|
);
|
|
99
99
|
let itemType$1 = (isIdsFieldName(fieldName) || isIdFieldName(fieldName)) && itemType === "ScalarString" ? "EntityId" : itemType;
|
|
@@ -120,7 +120,7 @@ function shapeOf(parentName, fieldName, schema) {
|
|
|
120
120
|
_1: fields
|
|
121
121
|
};
|
|
122
122
|
}
|
|
123
|
-
case "
|
|
123
|
+
case "anyOf" :
|
|
124
124
|
let anyOf = schema.anyOf;
|
|
125
125
|
let nonNullVariants = anyOf.filter(v => {
|
|
126
126
|
switch (v.type) {
|
|
@@ -173,7 +173,7 @@ function optionalFieldNames(schema) {
|
|
|
173
173
|
if (schema.type === "object") {
|
|
174
174
|
return Stdlib_Array.filterMap(Object.entries(schema.properties), param => {
|
|
175
175
|
let propSchema = param[1];
|
|
176
|
-
if (propSchema.type === "
|
|
176
|
+
if (propSchema.type === "anyOf" && propSchema.anyOf.some(v => {
|
|
177
177
|
switch (v.type) {
|
|
178
178
|
case "null" :
|
|
179
179
|
case "undefined" :
|
|
@@ -78,7 +78,7 @@ to qualify a store the annotation left unqualified.
|
|
|
78
78
|
*/
|
|
79
79
|
let fromEventSchema = (~plugin: string, eventSchema: S.t<unknown>): array<eventRefFields> =>
|
|
80
80
|
switch eventSchema {
|
|
81
|
-
|
|
|
81
|
+
| AnyOf({anyOf}) => anyOf->Array.filterMap(v => fromVariant(~plugin, v))
|
|
82
82
|
| other => fromVariant(~plugin, other)->Option.mapOr([], e => [e])
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -44,7 +44,7 @@ function fromVariant(plugin, variant) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
function fromEventSchema(plugin, eventSchema) {
|
|
47
|
-
if (eventSchema.type === "
|
|
47
|
+
if (eventSchema.type === "anyOf") {
|
|
48
48
|
return Stdlib_Array.filterMap(eventSchema.anyOf, v => fromVariant(plugin, v));
|
|
49
49
|
} else {
|
|
50
50
|
return Stdlib_Option.mapOr(fromVariant(plugin, eventSchema), [], e => [e]);
|
|
@@ -137,6 +137,14 @@ let mergeAnnotations = (
|
|
|
137
137
|
}
|
|
138
138
|
let entries =
|
|
139
139
|
r.label === "" ? entries : Array.concat([("label", JSON.Encode.string(r.label))], entries)
|
|
140
|
+
// `namedWhenRetired` travels only when true, on the omit-the-default rule
|
|
141
|
+
// the keys above follow: false is what every record said before the opt-in
|
|
142
|
+
// existed, and writing it would put a key on every retirement to say
|
|
143
|
+
// nothing changed.
|
|
144
|
+
let entries =
|
|
145
|
+
r.namedWhenRetired
|
|
146
|
+
? Array.concat(entries, [("namedWhenRetired", JSON.Encode.bool(true))])
|
|
147
|
+
: entries
|
|
140
148
|
obj->Dict.set("x-reventless-retired", JSON.Encode.object(Dict.fromArray(entries)))
|
|
141
149
|
| _ => ()
|
|
142
150
|
}
|
|
@@ -255,8 +263,19 @@ and objectRefToJsonSchema = (
|
|
|
255
263
|
): JSON.t => {
|
|
256
264
|
let props = Dict.make()
|
|
257
265
|
let required: array<string> = []
|
|
266
|
+
// `@internal` fields are dropped rather than annotated. A marker would be the
|
|
267
|
+
// right answer for a field that is on the surface and merely unwanted (that is
|
|
268
|
+
// `@hidden`); this one is not on the surface at all, so there is nothing for a
|
|
269
|
+
// consumer to describe and an entry here would advertise a field the SDL does
|
|
270
|
+
// not declare — which is precisely the mismatch that made read-model queries
|
|
271
|
+
// reference fields the server rejects.
|
|
272
|
+
//
|
|
273
|
+
// This is the single point for every JSON-Schema consumer: `queryableDef.schema`,
|
|
274
|
+
// the MCP generator and the manifest all derive through this walk.
|
|
275
|
+
let internal = annotations->Option.flatMap(spec => spec.internal)->Option.getOr([])
|
|
258
276
|
fields
|
|
259
277
|
->Dict.toArray
|
|
278
|
+
->Array.filter(((fieldName, _)) => !(internal->Array.includes(fieldName)))
|
|
260
279
|
->Array.forEach(((fieldName, fieldType)) => {
|
|
261
280
|
let baseSchema = fromSchemaType(fieldType)
|
|
262
281
|
let withAnnotations = switch annotations {
|
|
@@ -119,20 +119,24 @@ function mergeAnnotations(fieldSchema, fieldName, spec) {
|
|
|
119
119
|
"label",
|
|
120
120
|
r.label
|
|
121
121
|
]].concat(entries$1);
|
|
122
|
-
|
|
122
|
+
let entries$4 = r.namedWhenRetired ? entries$3.concat([[
|
|
123
|
+
"namedWhenRetired",
|
|
124
|
+
true
|
|
125
|
+
]]) : entries$3;
|
|
126
|
+
obj["x-reventless-retired"] = Object.fromEntries(entries$4);
|
|
123
127
|
}
|
|
124
128
|
let match$4 = spec.metric.find(param => param[0] === fieldName);
|
|
125
129
|
if (match$4 !== undefined) {
|
|
126
130
|
let m = match$4[1];
|
|
127
|
-
let entries$
|
|
131
|
+
let entries$5 = [[
|
|
128
132
|
"aggregate",
|
|
129
133
|
m.aggregate
|
|
130
134
|
]];
|
|
131
|
-
let entries$
|
|
135
|
+
let entries$6 = m.label === "" ? entries$5 : entries$5.concat([[
|
|
132
136
|
"label",
|
|
133
137
|
m.label
|
|
134
138
|
]]);
|
|
135
|
-
obj["x-reventless-metric"] = Object.fromEntries(entries$
|
|
139
|
+
obj["x-reventless-metric"] = Object.fromEntries(entries$6);
|
|
136
140
|
}
|
|
137
141
|
return obj;
|
|
138
142
|
}
|
|
@@ -277,7 +281,8 @@ function objectRefToJsonSchema(annotations, optionalOpt, ownersOpt, fields) {
|
|
|
277
281
|
let owners = ownersOpt !== undefined ? ownersOpt : [];
|
|
278
282
|
let props = {};
|
|
279
283
|
let required = [];
|
|
280
|
-
|
|
284
|
+
let internal = Stdlib_Option.getOr(Stdlib_Option.flatMap(annotations, spec => spec.internal), []);
|
|
285
|
+
Object.entries(fields).filter(param => !internal.includes(param[0])).forEach(param => {
|
|
281
286
|
let fieldType = param[1];
|
|
282
287
|
let fieldName = param[0];
|
|
283
288
|
let baseSchema = fromSchemaType(fieldType);
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
S.enableJson()
|
|
2
1
|
// AutomationSlice callback — implements the TODO list pattern with mixed-source
|
|
3
2
|
// dispatch (Plan 04).
|
|
4
3
|
//
|
|
@@ -143,7 +142,7 @@ module Make = (
|
|
|
143
142
|
| Some(_) => () // Already exists — skip
|
|
144
143
|
| None =>
|
|
145
144
|
let row: todoRow = {
|
|
146
|
-
item: item->
|
|
145
|
+
item: item->Reventless.Util_Sury.toJson(Spec.todoItemSchema),
|
|
147
146
|
status: Pending,
|
|
148
147
|
createdAt: now(),
|
|
149
148
|
retryCount: 0,
|
|
@@ -198,7 +197,7 @@ module Make = (
|
|
|
198
197
|
let commands = []
|
|
199
198
|
|
|
200
199
|
pending->Array.forEach(((id, row)) => {
|
|
201
|
-
let item = try row.item->
|
|
200
|
+
let item = try row.item->Reventless.Util_Sury.fromJson(Spec.todoItemSchema)->Some catch {
|
|
202
201
|
| exn =>
|
|
203
202
|
let errMsg =
|
|
204
203
|
exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("unknown")
|
|
@@ -214,7 +213,7 @@ module Make = (
|
|
|
214
213
|
| Some((targetId, command)) =>
|
|
215
214
|
todoItems->Dict.set(id, {...row, status: Processing, processedAt: now()})
|
|
216
215
|
let commandJson = try command
|
|
217
|
-
->
|
|
216
|
+
->Reventless.Util_Sury.toJson(Spec.commandSchema)
|
|
218
217
|
->Some catch {
|
|
219
218
|
| exn =>
|
|
220
219
|
let errMsg =
|