@anthusai/papyrus 1.0.0-next.39 → 1.0.0-next.40

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.
@@ -0,0 +1,26 @@
1
+ import { NestedStack } from "aws-cdk-lib";
2
+ export const DEFAULT_RESOLVER_WAVE_SIZE = 12;
3
+ export function planResolverWaves(items, waveSize) {
4
+ if (!Number.isInteger(waveSize) || waveSize < 1) {
5
+ return [];
6
+ }
7
+ const waves = [];
8
+ for (let start = 0; start < items.length; start += waveSize) {
9
+ waves.push(items.slice(start, start + waveSize));
10
+ }
11
+ return waves;
12
+ }
13
+ export function orderModelStacksInWaves(graphqlApi, modelNames, waveSize) {
14
+ const modelStacks = modelNames
15
+ .map((modelName) => graphqlApi.node.tryFindChild(modelName))
16
+ .filter((child) => child instanceof NestedStack);
17
+ const waves = planResolverWaves(modelStacks, waveSize);
18
+ for (let waveIndex = 1; waveIndex < waves.length; waveIndex += 1) {
19
+ for (const stack of waves[waveIndex]) {
20
+ for (const previousStack of waves[waveIndex - 1]) {
21
+ stack.addDependency(previousStack);
22
+ }
23
+ }
24
+ }
25
+ return waves.length;
26
+ }
@@ -0,0 +1,34 @@
1
+ import { NestedStack } from "aws-cdk-lib";
2
+ import type { IConstruct } from "constructs";
3
+
4
+ export const DEFAULT_RESOLVER_WAVE_SIZE = 12;
5
+
6
+ export function planResolverWaves<T>(items: T[], waveSize: number): T[][] {
7
+ if (!Number.isInteger(waveSize) || waveSize < 1) {
8
+ return [];
9
+ }
10
+ const waves: T[][] = [];
11
+ for (let start = 0; start < items.length; start += waveSize) {
12
+ waves.push(items.slice(start, start + waveSize));
13
+ }
14
+ return waves;
15
+ }
16
+
17
+ export function orderModelStacksInWaves(
18
+ graphqlApi: IConstruct,
19
+ modelNames: string[],
20
+ waveSize: number,
21
+ ): number {
22
+ const modelStacks = modelNames
23
+ .map((modelName) => graphqlApi.node.tryFindChild(modelName))
24
+ .filter((child): child is NestedStack => child instanceof NestedStack);
25
+ const waves = planResolverWaves(modelStacks, waveSize);
26
+ for (let waveIndex = 1; waveIndex < waves.length; waveIndex += 1) {
27
+ for (const stack of waves[waveIndex]) {
28
+ for (const previousStack of waves[waveIndex - 1]) {
29
+ stack.addDependency(previousStack);
30
+ }
31
+ }
32
+ }
33
+ return waves.length;
34
+ }
@@ -32,6 +32,13 @@ export type PapyrusSiteBackendConfig = {
32
32
  */
33
33
  productionAppId?: string;
34
34
  auth?: PapyrusAuthConfig;
35
+ /**
36
+ * Maximum number of data model nested stacks CloudFormation creates at once.
37
+ * Stacks are chained in waves of this size so a new AWS account is not hit
38
+ * with every AppSync CreateResolver call in parallel (429). Only adds
39
+ * DependsOn ordering; no resource changes. Default 12; 0 turns it off.
40
+ */
41
+ resolverWaveSize?: number;
35
42
  /** Static reader app (Markus-static sites) that a publish rebuilds through IAM `amplify:StartJob`. */
36
43
  reader?: { amplifyAppId: string; branchName?: string };
37
44
  /** Lets the newsroom start the `staging` branch build of this CMS app. */
@@ -6,6 +6,7 @@ import { CfnEventSourceMapping, FunctionUrlAuthType } from "aws-cdk-lib/aws-lamb
6
6
  import { CfnIndex, CfnVectorBucket, CfnVectorBucketPolicy } from "aws-cdk-lib/aws-s3vectors";
7
7
  import { dirname, resolve } from "node:path";
8
8
  import { fileURLToPath } from "node:url";
9
+ import { DEFAULT_RESOLVER_WAVE_SIZE, orderModelStacksInWaves } from "./resolver-waves.js";
9
10
  import { rebuildTriggerSettings } from "./rebuild-trigger-settings.js";
10
11
  import { applyCognitoDomainPrefix, authConfigFromEnv, defineSiteAuth } from "./auth/resource.js";
11
12
  import { data } from "./data/resource.js";
@@ -78,6 +79,7 @@ export function defineSiteBackend(papyrusSite) {
78
79
  slackDelivery,
79
80
  storage,
80
81
  });
82
+ orderModelStacksInWaves(backend.data.resources.graphqlApi.node.scope, Object.keys(backend.data.resources.tables), site.resolverWaveSize ?? DEFAULT_RESOLVER_WAVE_SIZE);
81
83
  const requestedCognitoDomainPrefix = (authConfig.cognitoDomainPrefix ?? "").trim();
82
84
  if (authConfig.applyCognitoDomainPrefix === true
83
85
  && requestedCognitoDomainPrefix !== ""
@@ -6,8 +6,10 @@ import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
6
6
  import { CfnEventSourceMapping, Function as LambdaFunction, FunctionUrlAuthType } from "aws-cdk-lib/aws-lambda";
7
7
  import * as s3 from "aws-cdk-lib/aws-s3";
8
8
  import { CfnIndex, CfnVectorBucket, CfnVectorBucketPolicy } from "aws-cdk-lib/aws-s3vectors";
9
+ import type { Construct } from "constructs";
9
10
  import { dirname, resolve } from "node:path";
10
11
  import { fileURLToPath } from "node:url";
12
+ import { DEFAULT_RESOLVER_WAVE_SIZE, orderModelStacksInWaves } from "./resolver-waves";
11
13
  import { rebuildTriggerSettings } from "./rebuild-trigger-settings";
12
14
  import { applyCognitoDomainPrefix, authConfigFromEnv, defineSiteAuth } from "./auth/resource";
13
15
  import { data } from "./data/resource";
@@ -96,6 +98,12 @@ export function defineSiteBackend(papyrusSite: PapyrusSite) {
96
98
  storage,
97
99
  });
98
100
 
101
+ orderModelStacksInWaves(
102
+ backend.data.resources.graphqlApi.node.scope as Construct,
103
+ Object.keys(backend.data.resources.tables),
104
+ site.resolverWaveSize ?? DEFAULT_RESOLVER_WAVE_SIZE,
105
+ );
106
+
99
107
  const requestedCognitoDomainPrefix = (authConfig.cognitoDomainPrefix ?? "").trim();
100
108
  if (
101
109
  authConfig.applyCognitoDomainPrefix === true
package/package.json CHANGED
@@ -302,7 +302,7 @@
302
302
  "optional": true
303
303
  }
304
304
  },
305
- "version": "1.0.0-next.39",
305
+ "version": "1.0.0-next.40",
306
306
  "dependencies": {
307
307
  "@aws-amplify/adapter-nextjs": "^1.7.3",
308
308
  "@aws-sdk/client-cognito-identity-provider": "3.1045.0",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.0-next.39",
2
+ "version": "1.0.0-next.40",
3
3
  "routes": [
4
4
  {
5
5
  "file": "app/%5F_preview/[[...path]]/route.ts",