@reventlessdev/reventless-aws 3.0.0-alpha.210 → 3.0.0-alpha.211

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/package.json +6 -6
  3. package/src/Platform.res +116 -849
  4. package/src/Platform.res.mjs +75 -710
  5. package/src/adapter/QueryDb/PgQueryResolver_Builder.res +4 -47
  6. package/src/adapter/QueryDb/PgQueryResolver_Builder.res.mjs +1 -30
  7. package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res +0 -11
  8. package/src/adapter/QueryDb/QueryDbResolvers_AppSync.res.mjs +0 -5
  9. package/src/adapter/Runtime/SideEffectHandlerRuntime_Builder_Single.res +6 -7
  10. package/src/components/Api/AppSync_Adapter.res +13 -105
  11. package/src/components/Api/AppSync_Adapter.res.mjs +0 -52
  12. package/src/components/Api/AppSync_MergedApi.res +1 -1
  13. package/src/components/Api/AppSync_SdlDecorate.res +6 -65
  14. package/src/components/Api/AppSync_SdlDecorate.res.mjs +1 -31
  15. package/src/components/Plugin.res.mjs +1 -2
  16. package/tests/AppSync_AdapterTest.res +23 -15
  17. package/tests/AppSync_AdapterTest.res.mjs +18 -16
  18. package/tests/AppSync_SdlDecorateTest.res +9 -89
  19. package/tests/AppSync_SdlDecorateTest.res.mjs +7 -72
  20. package/tests/MCP_LambdaTest.res +4 -6
  21. package/tests/MCP_LambdaTest.res.mjs +2 -2
  22. package/src/adapter/Api/ApiFragmentDeregistration.res +0 -138
  23. package/src/adapter/Api/ApiFragmentDeregistration.res.mjs +0 -108
  24. package/src/adapter/Api/ApiSchemaPush.res +0 -79
  25. package/src/adapter/Api/ApiSchemaPush.res.mjs +0 -64
  26. package/src/adapter/Api/Platform_ApiFragments_Lambda.res +0 -222
  27. package/src/adapter/Api/Platform_ApiFragments_Lambda.res.mjs +0 -202
  28. package/src/adapter/QueryDb/NodeResolver_AppSync.res +0 -71
  29. package/src/adapter/QueryDb/NodeResolver_AppSync.res.mjs +0 -44
  30. package/src/adapter/Runtime/ApiSchemaPush_Runtime.mjs +0 -204
  31. package/tests/ApiSchemaPushTest.res +0 -32
  32. package/tests/ApiSchemaPushTest.res.mjs +0 -20
@@ -53,30 +53,10 @@ let registerNodeType = (~typeName: string, ~readModelName: string): unit =>
53
53
  // -- Provision --------------------------------------------------------------
54
54
  let bool = b => b ? "true" : "false"
55
55
 
56
- // One `node(id: ID!)` resolver on the shared data source → Invoke {kind:"node"}.
57
- let nodeResolverCode =
58
- `import { util } from '@aws-appsync/utils';
59
- export function request(ctx) {
60
- const id = ctx.identity;
61
- return {
62
- operation: 'Invoke',
63
- payload: {
64
- readModelName: '',
65
- kind: 'node',
66
- arguments: ctx.args,
67
- identity: id != null && id.sub != null
68
- ? { userId: id.sub, username: id.username, groups: id.claims?.['cognito:groups'] ?? [], claims: id.claims, provider: 'Cognito' }
69
- : id != null
70
- ? { userArn: id.userArn ?? null, accountId: id.accountId ?? null, username: id.username ?? null, provider: 'IAM' }
71
- : null
72
- }
73
- };
74
- }
75
- export function response(ctx) {
76
- if (ctx.error) util.error(ctx.error.message, ctx.error.type);
77
- return ctx.result;
78
- }
79
- `->Pulumi.Input.make
56
+ // (The shared `node(id: ID!)` resolver was removed with the Relay-node
57
+ // resolution of the merged-api plan: the root field is no longer emitted on
58
+ // AWS. The Pg Lambda's runtime `handleNode` + the nodeTypes env plumbing stay
59
+ // inert pending a future consumer.)
80
60
 
81
61
  // Serialize the shared connection config into the env-config JSON (same shape
82
62
  // EventCollectorRuntime_Builder_Single bakes into HANDLER_CONFIG).
@@ -87,13 +67,6 @@ let provision = (
87
67
  ~api: Pulumi.Output.t<AppSync.GraphQLApi.t>,
88
68
  ~selection: QueryDbBackend.selection,
89
69
  ~opts: Pulumi.ComponentResource.options,
90
- // The shared node(id) resolver is a single resolver on the API's Query.node
91
- // field. In plugin-stack mode each plugin stack deploys independently onto one
92
- // shared API, so only ONE stack may own that field — and a per-plugin node
93
- // resolver only knows its own plugin's types anyway. So node is provisioned in
94
- // monolithic mode only; plugin stacks pass false. (Node is not wired on the
95
- // DynamoDB path either — it stays a monolithic-only capability for now.)
96
- ~createNodeResolver: bool=true,
97
70
  ): unit => {
98
71
  // Join the resolver-binding registry (labelField/includeIdParam) with the
99
72
  // ReadModel runtime registry (specModulePath, pgBacked). Only read models
@@ -257,22 +230,6 @@ let provision = (
257
230
  ~opts=Some(customOpts),
258
231
  )
259
232
 
260
- // Shared node(id) resolver (B3.2c) — one for the whole API, dispatched by
261
- // typeName in the Lambda. Only when some entity registered a node type
262
- // (else the `node` field isn't in the schema) AND in monolithic mode
263
- // (plugin stacks would collide on the single Query.node field).
264
- if createNodeResolver && nodeTypes->Dict.toArray->Array.length > 0 {
265
- let _nodeResolver = AppSync_Resolver_Retrying.makeUnitJsResolver(
266
- ~name=name ++ "NodeResolver",
267
- ~api,
268
- ~dataSourceName=dataSource.name->Pulumi.Output.asInput,
269
- ~type_="Query"->Pulumi.Input.make,
270
- ~field="node"->Pulumi.Input.make,
271
- ~code=nodeResolverCode,
272
- ~opts=customOpts,
273
- )
274
- }
275
-
276
233
  // Fulfil the deferred name the Postgres storage maker handed to resolvers.
277
234
  let _ = dataSource.name->Pulumi.Output.apply(n => resolveDataSourceName.contents(n))
278
235
  log.info(~comp="PgQueryResolver_Builder", `provisioned for ${handlers->Array.length->Int.toString} read model(s)`)
@@ -13,7 +13,6 @@ import * as PolicyDocument$PulumiAws from "@reventlessdev/rescript-pulumi-aws/sr
13
13
  import * as Util_Bundle$ReventlessAws from "../../util/Util_Bundle.res.mjs";
14
14
  import * as PgConnection$ReventlessAws from "../Postgres/PgConnection.res.mjs";
15
15
  import * as Util_Pulumi$ReventlessCore from "@reventlessdev/reventless-core/src/util/Util_Pulumi.res.mjs";
16
- import * as AppSync_Resolver_Retrying$ReventlessAws from "../Api/AppSync_Resolver_Retrying.res.mjs";
17
16
  import * as RuntimeEnvironment_Lambda$ReventlessAws from "../Runtime/RuntimeEnvironment_Lambda.res.mjs";
18
17
  import * as EventCollectorRuntime_Builder_Single$ReventlessAws from "../Runtime/EventCollectorRuntime_Builder_Single.res.mjs";
19
18
 
@@ -47,35 +46,11 @@ function bool(b) {
47
46
  }
48
47
  }
49
48
 
50
- let nodeResolverCode = `import { util } from '@aws-appsync/utils';
51
- export function request(ctx) {
52
- const id = ctx.identity;
53
- return {
54
- operation: 'Invoke',
55
- payload: {
56
- readModelName: '',
57
- kind: 'node',
58
- arguments: ctx.args,
59
- identity: id != null && id.sub != null
60
- ? { userId: id.sub, username: id.username, groups: id.claims?.['cognito:groups'] ?? [], claims: id.claims, provider: 'Cognito' }
61
- : id != null
62
- ? { userArn: id.userArn ?? null, accountId: id.accountId ?? null, username: id.username ?? null, provider: 'IAM' }
63
- : null
64
- }
65
- };
66
- }
67
- export function response(ctx) {
68
- if (ctx.error) util.error(ctx.error.message, ctx.error.type);
69
- return ctx.result;
70
- }
71
- `;
72
-
73
49
  function pgConnectionJson(cc) {
74
50
  return JSON.stringify(PgConnection$ReventlessAws.connectionConfigToJson(undefined, cc));
75
51
  }
76
52
 
77
- function provision(api, selection, opts, createNodeResolverOpt) {
78
- let createNodeResolver = createNodeResolverOpt !== undefined ? createNodeResolverOpt : true;
53
+ function provision(api, selection, opts) {
79
54
  let handlers = Stdlib_Array.filterMap(Object.values(entries), entry => {
80
55
  let info = EventCollectorRuntime_Builder_Single$ReventlessAws.readModelInfos[entry.readModelName];
81
56
  if (info !== undefined && info.pgBacked) {
@@ -147,9 +122,6 @@ function provision(api, selection, opts, createNodeResolverOpt) {
147
122
  },
148
123
  serviceRoleArn: dataSourceRole.arn
149
124
  }, customOpts);
150
- if (createNodeResolver && Object.entries(nodeTypes).length !== 0) {
151
- AppSync_Resolver_Retrying$ReventlessAws.makeUnitJsResolver(name + "NodeResolver", api, dataSource.name, "Query", "node", nodeResolverCode, customOpts);
152
- }
153
125
  dataSource.name.apply(n => resolveDataSourceName.contents(n));
154
126
  log.info("PgQueryResolver_Builder", undefined, `provisioned for ` + handlers.length.toString() + ` read model(s)`);
155
127
  }
@@ -166,7 +138,6 @@ export {
166
138
  nodeTypes,
167
139
  registerNodeType,
168
140
  bool,
169
- nodeResolverCode,
170
141
  pgConnectionJson,
171
142
  provision,
172
143
  }
@@ -105,17 +105,6 @@ let make: ReventlessCore.QueryDb_Adapter.resolversMaker<api, role> = (
105
105
  | None => true
106
106
  }
107
107
 
108
- // Resolve returnTypeName for Relay Node type registry
109
- let returnTypeName = switch registryEntry {
110
- | Some({returnTypeName: rt}) => rt
111
- | None => name
112
- }
113
-
114
- // Register entity type in the Relay Node type registry for node(id: ID!) resolution
115
- if includeIdParam {
116
- NodeResolver_AppSync.registerNodeType(~typeName=returnTypeName, ~dataSourceName)
117
- }
118
-
119
108
  // Creates either a unit resolver (no interceptor) or a pipeline resolver
120
109
  // (interceptor Lambda → DynamoDB query) depending on queryInterceptorConfig.
121
110
  let makeQueryResolver = (~resolverName, ~field, ~code) =>
@@ -11,7 +11,6 @@ import * as Util_DynamoDb$ReventlessAws from "../../util/Util_DynamoDb.res.mjs";
11
11
  import * as Util_QueryDb$ReventlessCore from "@reventlessdev/reventless-core/src/util/Util_QueryDb.res.mjs";
12
12
  import * as AppSync_DataSource$PulumiAws from "@reventlessdev/rescript-pulumi-aws/src/AppSync/AppSync_DataSource.res.mjs";
13
13
  import * as Plugin_Helpers$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/component/Plugin_Helpers.res.mjs";
14
- import * as NodeResolver_AppSync$ReventlessAws from "./NodeResolver_AppSync.res.mjs";
15
14
  import * as AppSync_Resolver_Functions$PulumiAws from "@reventlessdev/rescript-pulumi-aws/src/AppSync/AppSync_Resolver_Functions.res.mjs";
16
15
  import * as AppSync_Resolver_Retrying$ReventlessAws from "../Api/AppSync_Resolver_Retrying.res.mjs";
17
16
  import * as GraphQL_FragmentGenerator$ReventlessCore from "@reventlessdev/reventless-core/src/components/Api/GraphQL_FragmentGenerator.res.mjs";
@@ -70,10 +69,6 @@ function make(name, api, apiRole, dataSourceName, indexes, subIdField, idResolve
70
69
  let fieldNameForSingle = registryEntry !== undefined ? registryEntry.singleFieldName : AppSync_Resolver_Functions$PulumiAws.uncapitalize(name$1);
71
70
  let includeIdParam = registryEntry !== undefined ? registryEntry.includeIdParam : true;
72
71
  let connectionSpec = registryEntry !== undefined ? registryEntry.connectionSpec : true;
73
- let returnTypeName = registryEntry !== undefined ? registryEntry.returnTypeName : name$1;
74
- if (includeIdParam) {
75
- NodeResolver_AppSync$ReventlessAws.registerNodeType(returnTypeName, dataSourceName);
76
- }
77
72
  let makeQueryResolver = (resolverName, field, code) => {
78
73
  let match = queryInterceptorConfig.contents;
79
74
  if (match === undefined) {
@@ -15,7 +15,7 @@ let sideEffectInfos: dict<sideEffectInfo> = Dict.make()
15
15
  let registerSideEffectHandler = (~sideEffectHandlerName, ~sideEffectModulePaths) =>
16
16
  sideEffectInfos->Dict.set(sideEffectHandlerName, {sideEffectModulePaths: sideEffectModulePaths})
17
17
 
18
- // Extra Lambda env vars contributed by bespoke side effects (e.g. admin ApiSchemaPush).
18
+ // Extra Lambda env vars contributed by bespoke side effects.
19
19
  // The shared "AllSideEffectHandlers" Lambda is built once in finish(); all registered
20
20
  // entries are merged onto its env there. Deploy-derived config only — never overrides
21
21
  // HANDLER_CONFIG.
@@ -176,12 +176,11 @@ let finish = () =>
176
176
  ~opts,
177
177
  )
178
178
 
179
- // The admin ApiSchemaPush side effect (the only extra-env contributor) pushes the
180
- // stitched schema to AppSync via StartSchemaCreation and reads the live schema for
181
- // the shrink guard. Grant those AppSync perms to the shared side-effect-handler
182
- // Lambda role ONLY when a bespoke side effect registered config — Task-only
183
- // deployments keep the narrow default perimeter. Mirrors the admin EventCollector's
184
- // AllowAdminStartSchemaCreation grant (PluginRuntime_Builder).
179
+ // Grant AppSync schema perms to the shared side-effect-handler Lambda
180
+ // role ONLY when a bespoke side effect registered extra-env config
181
+ // Task-only deployments keep the narrow default perimeter. (The last
182
+ // such contributor, the admin ApiSchemaPush, was retired with the
183
+ // merged-API cutover; the mechanism stays for future bespoke effects.)
185
184
  if extraEnvVarsAll->Dict.keysToArray->Array.length > 0 {
186
185
  let _ = PulumiAws.IAM.RolePolicy.make(
187
186
  ~name="AllSideEffectHandlers-appsyncSchemaPush",
@@ -94,58 +94,6 @@ let rec waitForSchemaActive = async (client, apiId, ~maxAttempts=30, ~attempt=0)
94
94
  }
95
95
  }
96
96
 
97
- // GetIntrospectionSchema — fetch the live schema as an SDL string. Used by the
98
- // deploy-time drift check in preResolversSchemaHook to detect a live schema that
99
- // was clobbered out-of-band by a runtime re-stitch (the stored deploy hash does
100
- // not reflect such clobbers). Returns "" when the API has no schema or when
101
- // introspection fails — the caller decides how to treat an empty result.
102
- type getIntrospectionSchemaInput = {apiId: string, format: string}
103
- type getIntrospectionSchemaCommand
104
- type schemaBlob
105
- type getIntrospectionSchemaResult = {schema: option<schemaBlob>}
106
-
107
- @module("@aws-sdk/client-appsync") @new
108
- external makeGetIntrospectionSchemaCommand: getIntrospectionSchemaInput => getIntrospectionSchemaCommand =
109
- "GetIntrospectionSchemaCommand"
110
-
111
- @send
112
- external sendGetIntrospection: (
113
- appSyncClient,
114
- getIntrospectionSchemaCommand,
115
- ) => promise<getIntrospectionSchemaResult> = "send"
116
-
117
- // resp.schema is a Uint8Array of the SDL text; decode it to UTF-8.
118
- type nodeBuffer
119
- @val @scope("Buffer") external bufferFrom: schemaBlob => nodeBuffer = "from"
120
- @send external bufferToString: (nodeBuffer, string) => string = "toString"
121
-
122
- let getIntrospectionSdl = async (client: appSyncClient, apiId: string): string => {
123
- try {
124
- let resp = await client->sendGetIntrospection(
125
- {apiId, format: "SDL"}->makeGetIntrospectionSchemaCommand,
126
- )
127
- switch resp.schema {
128
- | Some(blob) => bufferFrom(blob)->bufferToString("utf-8")
129
- | None => ""
130
- }
131
- } catch {
132
- | exn =>
133
- let msg = exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("unknown")
134
- log.warn(~comp="AppSync_Adapter", `getIntrospectionSdl failed for ${apiId}: ${msg}`)
135
- ""
136
- }
137
- }
138
-
139
- let deploySchemaWithRetry = (
140
- client: appSyncClient,
141
- apiId: string,
142
- definition: string,
143
- ): Effect.t<unit, AppSync_Error.t, unit> =>
144
- Effect.tryPromise(
145
- ~catch=AppSync_Error.classify,
146
- () => startSchemaCreation(client, {apiId, definition})->Promise.then(_ => Promise.resolve()),
147
- )->Effect.retry(AppSync_Error.retrySchedule)
148
-
149
97
  // Lazy singleton AppSync client (runtime only)
150
98
  let _client: ref<option<appSyncClient>> = ref(None)
151
99
  let getClient = () =>
@@ -484,32 +432,16 @@ let injectAwsAuthAll = (
484
432
  AppSync_SdlDecorate.injectAwsAuthAll(fragment, ~group, ~iamFieldNames)
485
433
 
486
434
  /**
487
- Stitch base + plugin fragments and decorate the assembled SDL with the AppSync
488
- dialect: `@aws_subscribe` on mutation-sourced subscription fields (from the
489
- fragments' neutral `subscriptionSources` metadata core no longer emits the
490
- directive) and `@aws_cognito_user_pools @aws_iam` on the shared traversal
491
- types. Every AWS schema push assembles its SDL through here so the dialect is
492
- applied uniformly.
493
- */
494
- let stitchWithAwsDirectives = (
495
- ~baseFragment: Reventless.Plugin.apiSchemaFragment,
496
- ~pluginFragments: array<Reventless.Plugin.apiSchemaFragment>,
497
- ): string => {
498
- let sources = ReventlessCore.GraphQL_Stitcher.collectSubscriptionSources(
499
- ~baseFragment,
500
- ~pluginFragments,
501
- )
502
- ReventlessCore.GraphQL_Stitcher.stitch(~baseFragment, ~pluginFragments)
503
- ->AppSync_SdlDecorate.injectAwsSubscribe(~sources)
504
- ->stampSharedIamTypes
505
- }
506
-
507
- /**
508
- Merged-mode plugin subgraph document: one fragment rendered standalone
509
- (relay base types included, global `node` omitted — only the platform's
510
- canonical base document carries `node`), with the same AppSync dialect as
511
- `stitchWithAwsDirectives`. No `@canonical` stamps — plugin subgraphs stay
512
- unstamped; the admin source's canonical definitions win on merge.
435
+ One source-API document rendered standalone (relay base types included; the
436
+ global `node` query is not emitted on AWS see the merged-api plan's "Relay
437
+ node resolution" section), decorated with the AppSync dialect:
438
+ `@aws_subscribe` on mutation-sourced subscription fields (from the fragment's
439
+ neutral `subscriptionSources` metadata) and `@aws_cognito_user_pools @aws_iam`
440
+ on the shared traversal types. Every AWS source-API document — the platform's
441
+ canonical documents and each plugin's subgraph — assembles through here so the
442
+ dialect is applied uniformly. No `@canonical` stamps here — the platform adds
443
+ them to its canonical documents only; plugin subgraphs stay unstamped and the
444
+ canonical definitions win on merge.
513
445
  */
514
446
  let stitchStandaloneWithAwsDirectives = (
515
447
  ~fragment: Reventless.Plugin.apiSchemaFragment,
@@ -634,30 +566,6 @@ let generateFragment = (
634
566
  injectAwsAuth(fragment, ~mutationEntries, ~queryEntries)
635
567
  }
636
568
 
637
- let updateSchema = (
638
- ~api: Pulumi.Output.t<api>,
639
- ~baseFragment: Reventless.Plugin.apiSchemaFragment,
640
- ~pluginFragments: array<Reventless.Plugin.apiSchemaFragment>,
641
- ): promise<unit> => {
642
- // Inject @aws_auth(cognito_groups: ["Admin"]) into all base fragment fields.
643
- // The base fragment contains core Plugin aggregate queries/mutations — all Admin-only.
644
- // Plugin fragments already have @aws_auth injected via generateFragment.
645
- let augmentedBaseFragment = injectAwsAuthAll(baseFragment, ~group="Admin")
646
- // Shared traversal types + @aws_subscribe are stamped once on the assembled
647
- // SDL (post-stitch, post-dedupe) — see stitchWithAwsDirectives.
648
- let sdl = stitchWithAwsDirectives(~baseFragment=augmentedBaseFragment, ~pluginFragments)
649
- // Resolve the API ID from the Output chain. In mock mode (tests) and in Lambda runtime
650
- // (where the Output is backed by already-known values), this completes synchronously.
651
- // The resulting promise wraps the AppSync SDK call.
652
- let resultPromise: ref<promise<unit>> = ref(Promise.resolve())
653
- let _ =
654
- api
655
- ->Pulumi.Output.apply(graphQLApi =>
656
- graphQLApi.id->Pulumi.Output.apply(apiId => {
657
- let effect = deploySchemaWithRetry(getClient(), apiId, sdl)
658
- let p = effect->Effect.runPromise
659
- resultPromise.contents = p
660
- })
661
- )
662
- resultPromise.contents
663
- }
569
+ // (updateSchema the whole-replace stitched-schema push — was retired with
570
+ // the merged-API cutover; every source API owns its schema declaratively or
571
+ // via its own single-writer subgraph push in preResolversSchemaHook.)
@@ -4,14 +4,12 @@ import * as Effect from "@reventlessdev/rescript-effect/src/Effect.res.mjs";
4
4
  import * as Aws from "@pulumi/aws";
5
5
  import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
6
6
  import * as Nodecrypto from "node:crypto";
7
- import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
8
7
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
9
8
  import * as Stdlib_String from "@rescript/runtime/lib/es6/Stdlib_String.js";
10
9
  import * as Effect$1 from "effect/Effect";
11
10
  import * as Pulumi from "@pulumi/pulumi";
12
11
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
13
12
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
14
- import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
15
13
  import * as Logger$ReventlessCore from "@reventlessdev/reventless-core/src/util/Logger.res.mjs";
16
14
  import * as ClientAppsync from "@aws-sdk/client-appsync";
17
15
  import * as Auth_Cognito$ReventlessAws from "../../adapter/Auth/Auth_Cognito.res.mjs";
@@ -60,33 +58,6 @@ async function waitForSchemaActive(client, apiId, maxAttemptsOpt, attemptOpt) {
60
58
  }
61
59
  }
62
60
 
63
- async function getIntrospectionSdl(client, apiId) {
64
- try {
65
- let resp = await client.send(new ClientAppsync.GetIntrospectionSchemaCommand({
66
- apiId: apiId,
67
- format: "SDL"
68
- }));
69
- let blob = resp.schema;
70
- if (blob !== undefined) {
71
- return Buffer.from(Primitive_option.valFromOption(blob)).toString("utf-8");
72
- } else {
73
- return "";
74
- }
75
- } catch (raw_exn) {
76
- let exn = Primitive_exceptions.internalToException(raw_exn);
77
- let msg = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "unknown");
78
- log.warn("AppSync_Adapter", undefined, `getIntrospectionSdl failed for ` + apiId + `: ` + msg);
79
- return "";
80
- }
81
- }
82
-
83
- function deploySchemaWithRetry(client, apiId, definition) {
84
- return Effect$1.retry(Effect.tryPromise(AppSync_Error$ReventlessAws.classify, () => client.send(new ClientAppsync.StartSchemaCreationCommand({
85
- apiId: apiId,
86
- definition: definition
87
- })).then(param => Promise.resolve())), AppSync_Error$ReventlessAws.retrySchedule);
88
- }
89
-
90
61
  let _client = {
91
62
  contents: undefined
92
63
  };
@@ -292,11 +263,6 @@ function injectAwsAuthAll(fragment, group, iamFieldNamesOpt) {
292
263
  return AppSync_SdlDecorate$ReventlessAws.injectAwsAuthAll(fragment, group, iamFieldNames);
293
264
  }
294
265
 
295
- function stitchWithAwsDirectives(baseFragment, pluginFragments) {
296
- let sources = GraphQL_Stitcher$ReventlessCore.collectSubscriptionSources(baseFragment, pluginFragments);
297
- return AppSync_SdlDecorate$ReventlessAws.stampSharedIamTypes(AppSync_SdlDecorate$ReventlessAws.injectAwsSubscribe(GraphQL_Stitcher$ReventlessCore.stitch(baseFragment, pluginFragments), sources));
298
- }
299
-
300
266
  function stitchStandaloneWithAwsDirectives(fragment) {
301
267
  let sources = GraphQL_Stitcher$ReventlessCore.collectSubscriptionSources(fragment, []);
302
268
  return AppSync_SdlDecorate$ReventlessAws.stampSharedIamTypes(AppSync_SdlDecorate$ReventlessAws.injectAwsSubscribe(GraphQL_Stitcher$ReventlessCore.stitchStandalone(fragment), sources));
@@ -350,20 +316,6 @@ function generateFragment(mutationEntries, queryEntries) {
350
316
  return injectAwsAuth(fragment, mutationEntries, queryEntries);
351
317
  }
352
318
 
353
- function updateSchema(api, baseFragment, pluginFragments) {
354
- let augmentedBaseFragment = injectAwsAuthAll(baseFragment, "Admin", undefined);
355
- let sdl = stitchWithAwsDirectives(augmentedBaseFragment, pluginFragments);
356
- let resultPromise = {
357
- contents: Promise.resolve()
358
- };
359
- api.apply(graphQLApi => graphQLApi.id.apply(apiId => {
360
- let effect = deploySchemaWithRetry(getClient(), apiId, sdl);
361
- let p = Effect$1.runPromise(effect);
362
- resultPromise.contents = p;
363
- }));
364
- return resultPromise.contents;
365
- }
366
-
367
319
  let stampSharedIamTypes = AppSync_SdlDecorate$ReventlessAws.stampSharedIamTypes;
368
320
 
369
321
  let primaryAuthenticationType = "AMAZON_COGNITO_USER_POOLS";
@@ -374,8 +326,6 @@ export {
374
326
  startSchemaCreation,
375
327
  startSchemaCreationRetrying,
376
328
  waitForSchemaActive,
377
- getIntrospectionSdl,
378
- deploySchemaWithRetry,
379
329
  _client,
380
330
  getClient,
381
331
  waitForMergeSuccess,
@@ -387,7 +337,6 @@ export {
387
337
  stampSharedIamTypes,
388
338
  injectAwsAuth,
389
339
  injectAwsAuthAll,
390
- stitchWithAwsDirectives,
391
340
  stitchStandaloneWithAwsDirectives,
392
341
  primaryAuthenticationType,
393
342
  _makeApiResourceWith,
@@ -395,6 +344,5 @@ export {
395
344
  makeSourceApiResource,
396
345
  makePluginSourceApiResource,
397
346
  generateFragment,
398
- updateSchema,
399
347
  }
400
348
  /* log Not a pure module */
@@ -1,5 +1,5 @@
1
1
  // AppSync_MergedApi — merged-API construction for the push-free composition
2
- // path (docs/plans/merged-api-push-free-composition.md, Phase 3).
2
+ // path (docs/plans/done/merged-api-push-free-composition.md, Phase 3).
3
3
  //
4
4
  // A merged API carries no schema of its own: source APIs contribute theirs via
5
5
  // SourceApiAssociation and AWS composes the merged endpoint. The platform
@@ -119,19 +119,14 @@ let injectAwsAuthAll = (
119
119
  }
120
120
 
121
121
  // Shared traversal types every callable surface reaches — `PageInfo` (relay
122
- // connections, injected by the stitcher), the `CommandResult` members (mutation
123
- // returns, deduped across fragments by the stitcher), and `Platform_ApiFragmentEntry`
124
- // (the return type of the IAM-callable `Platform_ApiFragments` status query the deploy
125
- // waiter polls via SigV4 — without the type-level `@aws_iam` the SigV4 caller reaches the
126
- // query field but is "Not Authorized to access <field> on type Platform_ApiFragmentEntry").
127
- // Stamped once on the ASSEMBLED SDL: per-fragment stamping would race the stitcher's
128
- // first-wins dedupe against unstamped sibling copies.
122
+ // connections, injected by the stitcher) and the `CommandResult` members
123
+ // (mutation returns). Stamped once on the ASSEMBLED SDL so an IAM system
124
+ // caller (`@@reventless.systemCallable` fields) can traverse them.
129
125
  let sharedIamTypeNames = [
130
126
  "PageInfo",
131
127
  "CommandAccepted",
132
128
  "CommandRejected",
133
129
  "CommandPending",
134
- "Platform_ApiFragmentEntry",
135
130
  ]
136
131
 
137
132
  let stampSharedIamTypes = (sdl: string): string =>
@@ -186,60 +181,6 @@ let stampCanonicalTypes = (sdl: string): string =>
186
181
  })
187
182
  ->Array.join("\n")
188
183
 
189
- // ── Reactive push planner (runtime-pure) ─────────────────────────────────────
190
- // The AWS-decorated counterpart of core `GraphQL_PushPlanner.planPushes`: given
191
- // the fragments currently in the ApiFragmentRegistry (each tagged with its target
192
- // API, as the bare string "Domain" / "Platform"), it produces one fully
193
- // AppSync-decorated SDL push plan per API. It reuses the core planner for the
194
- // neutral base-selection + stitch, then applies the AppSync dialect exactly as the
195
- // deploy path's `stitchWithAwsDirectives`:
196
- // - the admin base is auth-decorated (group "Admin" + dual-auth on the system-
197
- // caller field names) BEFORE stitching, so the Platform/unified base carries
198
- // @aws_auth/@aws_iam (the empty Domain-split base needs none);
199
- // - @aws_subscribe is injected from the neutral subscriptionSources metadata;
200
- // - the shared traversal types are stamped once on the assembled SDL.
201
- // Plugin fragments already carry their own per-field @aws_auth (baked at
202
- // generateFragment time), so they stitch in as-is. `api` comes back as the bare
203
- // string "PlatformApi" / "DomainApi" for the mjs to map onto the AppSync ids.
204
- type targetedFragmentInput = {
205
- encoded: string,
206
- protocol: string,
207
- // "Domain" | "Platform" — the bare-string runtime form of Reventless.Plugin.apiTarget.
208
- target: string,
209
- }
210
-
211
- type awsPushPlan = {
212
- // "PlatformApi" | "DomainApi" — the bare-string runtime form of GraphQL_PushPlanner.planTarget.
213
- api: string,
214
- sdl: string,
215
- }
216
-
217
- let planAwsPushes = (
218
- ~rawAdminBase: Reventless.Plugin.apiSchemaFragment,
219
- ~iamFieldNames: array<string>,
220
- ~fragments: array<targetedFragmentInput>,
221
- ~splitApi: bool,
222
- ): array<awsPushPlan> => {
223
- let authBase = injectAwsAuthAll(rawAdminBase, ~group="Admin", ~iamFieldNames)
224
- let targeted = fragments->Array.map((f): ReventlessCore.GraphQL_PushPlanner.targetedFragment => {
225
- fragment: {encoded: f.encoded, protocol: f.protocol},
226
- target: switch f.target {
227
- | "Platform" => Platform
228
- | _ => Domain
229
- },
230
- })
231
- let allFrags = targeted->Array.map(t => t.fragment)
232
- let sources = ReventlessCore.GraphQL_Stitcher.collectSubscriptionSources(
233
- ~baseFragment=rawAdminBase,
234
- ~pluginFragments=allFrags,
235
- )
236
- ReventlessCore.GraphQL_PushPlanner.planPushes(~adminBase=authBase, ~fragments=targeted, ~splitApi)
237
- ->Array.map(plan => {
238
- let sdl = plan.sdl->injectAwsSubscribe(~sources)->stampSharedIamTypes
239
- let api = switch plan.api {
240
- | PlatformApi => "PlatformApi"
241
- | DomainApi => "DomainApi"
242
- }
243
- {api, sdl}
244
- })
245
- }
184
+ // (The reactive push planner planAwsPushes, the AWS counterpart of core
185
+ // GraphQL_PushPlanner was retired with the merged-API cutover: source APIs
186
+ // are single writers, AWS composes the merged endpoint, nothing re-stitches.)
@@ -3,7 +3,6 @@
3
3
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
4
4
  import * as Stdlib_String from "@rescript/runtime/lib/es6/Stdlib_String.js";
5
5
  import * as GraphQL_Stitcher$ReventlessCore from "@reventlessdev/reventless-core/src/components/Api/GraphQL_Stitcher.res.mjs";
6
- import * as GraphQL_PushPlanner$ReventlessCore from "@reventlessdev/reventless-core/src/components/Api/GraphQL_PushPlanner.res.mjs";
7
6
 
8
7
  function injectAwsSubscribe(sdl, sources) {
9
8
  if (sources.length === 0) {
@@ -80,8 +79,7 @@ let sharedIamTypeNames = [
80
79
  "PageInfo",
81
80
  "CommandAccepted",
82
81
  "CommandRejected",
83
- "CommandPending",
84
- "Platform_ApiFragmentEntry"
82
+ "CommandPending"
85
83
  ];
86
84
 
87
85
  function stampSharedIamTypes(sdl) {
@@ -125,33 +123,6 @@ function stampCanonicalTypes(sdl) {
125
123
  }).join("\n");
126
124
  }
127
125
 
128
- function planAwsPushes(rawAdminBase, iamFieldNames, fragments, splitApi) {
129
- let authBase = injectAwsAuthAll(rawAdminBase, "Admin", iamFieldNames);
130
- let targeted = fragments.map(f => {
131
- let match = f.target;
132
- let tmp = match === "Platform" ? "Platform" : "Domain";
133
- return {
134
- fragment: {
135
- encoded: f.encoded,
136
- protocol: f.protocol
137
- },
138
- target: tmp
139
- };
140
- });
141
- let allFrags = targeted.map(t => t.fragment);
142
- let sources = GraphQL_Stitcher$ReventlessCore.collectSubscriptionSources(rawAdminBase, allFrags);
143
- return GraphQL_PushPlanner$ReventlessCore.planPushes(authBase, targeted, splitApi).map(plan => {
144
- let sdl = stampSharedIamTypes(injectAwsSubscribe(plan.sdl, sources));
145
- let match = plan.api;
146
- let api;
147
- api = match === "DomainApi" ? "DomainApi" : "PlatformApi";
148
- return {
149
- api: api,
150
- sdl: sdl
151
- };
152
- });
153
- }
154
-
155
126
  export {
156
127
  injectAwsSubscribe,
157
128
  formatDualAuthDirective,
@@ -160,6 +131,5 @@ export {
160
131
  stampSharedIamTypes,
161
132
  canonicalTypeNames,
162
133
  stampCanonicalTypes,
163
- planAwsPushes,
164
134
  }
165
135
  /* GraphQL_Stitcher-ReventlessCore Not a pure module */
@@ -28,8 +28,7 @@ function Make(HooksConfig) {
28
28
  hooks: HooksConfig.hooks
29
29
  })({})({
30
30
  makeApiResource: AppSync_Adapter$ReventlessAws.makeApiResource,
31
- generateFragment: AppSync_Adapter$ReventlessAws.generateFragment,
32
- updateSchema: AppSync_Adapter$ReventlessAws.updateSchema
31
+ generateFragment: AppSync_Adapter$ReventlessAws.generateFragment
33
32
  })({
34
33
  make: RuntimeEnvironment_Lambda$ReventlessAws.make,
35
34
  groupBySource: RuntimeEnvironment_Lambda$ReventlessAws.groupBySource,