qlara 0.1.4 → 0.1.5

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/dist/aws.cjs CHANGED
@@ -69,12 +69,12 @@ function getContentType(filePath) {
69
69
  const ext = (0, import_node_path.extname)(filePath).toLowerCase();
70
70
  return CONTENT_TYPES[ext] || "application/octet-stream";
71
71
  }
72
- function getCacheControl(key) {
72
+ function getCacheControl(key, cacheTtl) {
73
73
  if (key.includes("_next/static/") || key.includes(".chunk.")) {
74
74
  return "public, max-age=31536000, immutable";
75
75
  }
76
76
  if (key.endsWith(".html")) {
77
- return "public, max-age=0, must-revalidate";
77
+ return `public, max-age=0, s-maxage=${cacheTtl}, stale-while-revalidate=60`;
78
78
  }
79
79
  return "public, max-age=86400";
80
80
  }
@@ -112,7 +112,7 @@ async function listAllKeys(client, bucketName) {
112
112
  } while (continuationToken);
113
113
  return keys;
114
114
  }
115
- async function syncToS3(client, bucketName, buildDir) {
115
+ async function syncToS3(client, bucketName, buildDir, cacheTtl = 3600) {
116
116
  const files = listFiles(buildDir);
117
117
  const newKeys = /* @__PURE__ */ new Set();
118
118
  let uploaded = 0;
@@ -125,7 +125,7 @@ async function syncToS3(client, bucketName, buildDir) {
125
125
  newKeys.add(key);
126
126
  const body = (0, import_node_fs.readFileSync)(filePath);
127
127
  const contentType = getContentType(filePath);
128
- const cacheControl = getCacheControl(key);
128
+ const cacheControl = getCacheControl(key, cacheTtl);
129
129
  await client.send(
130
130
  new import_client_s3.PutObjectCommand({
131
131
  Bucket: bucketName,
@@ -878,7 +878,7 @@ function aws(awsConfig = {}) {
878
878
  console.log(`[qlara/aws] Generated ${fallbacks.length} fallback page(s)`);
879
879
  console.log("[qlara/aws] Syncing build output to S3...");
880
880
  const s3 = createS3Client(res.region);
881
- const { uploaded, deleted } = await syncToS3(s3, res.bucketName, buildDir);
881
+ const { uploaded, deleted } = await syncToS3(s3, res.bucketName, buildDir, cacheTtl);
882
882
  console.log(`[qlara/aws] Uploaded ${uploaded} files, deleted ${deleted} stale files`);
883
883
  console.log("[qlara/aws] Bundling edge handler...");
884
884
  const edgeZip = await bundleEdgeHandler({
@@ -896,7 +896,8 @@ function aws(awsConfig = {}) {
896
896
  await lambda.send(
897
897
  new import_client_lambda.UpdateFunctionConfigurationCommand({
898
898
  FunctionName: res.edgeFunctionArn,
899
- Timeout: 30
899
+ Timeout: 30,
900
+ MemorySize: 512
900
901
  })
901
902
  );
902
903
  await (0, import_client_lambda.waitUntilFunctionUpdatedV2)(
@@ -983,7 +984,7 @@ function aws(awsConfig = {}) {
983
984
  new import_client_lambda.UpdateFunctionConfigurationCommand({
984
985
  FunctionName: res.rendererFunctionArn,
985
986
  Layers: [],
986
- MemorySize: 256,
987
+ MemorySize: 512,
987
988
  Timeout: 30,
988
989
  Environment: {
989
990
  Variables: config.env ?? {}
package/dist/aws.js CHANGED
@@ -66,12 +66,12 @@ function getContentType(filePath) {
66
66
  const ext = extname(filePath).toLowerCase();
67
67
  return CONTENT_TYPES[ext] || "application/octet-stream";
68
68
  }
69
- function getCacheControl(key) {
69
+ function getCacheControl(key, cacheTtl) {
70
70
  if (key.includes("_next/static/") || key.includes(".chunk.")) {
71
71
  return "public, max-age=31536000, immutable";
72
72
  }
73
73
  if (key.endsWith(".html")) {
74
- return "public, max-age=0, must-revalidate";
74
+ return `public, max-age=0, s-maxage=${cacheTtl}, stale-while-revalidate=60`;
75
75
  }
76
76
  return "public, max-age=86400";
77
77
  }
@@ -109,7 +109,7 @@ async function listAllKeys(client, bucketName) {
109
109
  } while (continuationToken);
110
110
  return keys;
111
111
  }
112
- async function syncToS3(client, bucketName, buildDir) {
112
+ async function syncToS3(client, bucketName, buildDir, cacheTtl = 3600) {
113
113
  const files = listFiles(buildDir);
114
114
  const newKeys = /* @__PURE__ */ new Set();
115
115
  let uploaded = 0;
@@ -122,7 +122,7 @@ async function syncToS3(client, bucketName, buildDir) {
122
122
  newKeys.add(key);
123
123
  const body = readFileSync(filePath);
124
124
  const contentType = getContentType(filePath);
125
- const cacheControl = getCacheControl(key);
125
+ const cacheControl = getCacheControl(key, cacheTtl);
126
126
  await client.send(
127
127
  new PutObjectCommand({
128
128
  Bucket: bucketName,
@@ -874,7 +874,7 @@ function aws(awsConfig = {}) {
874
874
  console.log(`[qlara/aws] Generated ${fallbacks.length} fallback page(s)`);
875
875
  console.log("[qlara/aws] Syncing build output to S3...");
876
876
  const s3 = createS3Client(res.region);
877
- const { uploaded, deleted } = await syncToS3(s3, res.bucketName, buildDir);
877
+ const { uploaded, deleted } = await syncToS3(s3, res.bucketName, buildDir, cacheTtl);
878
878
  console.log(`[qlara/aws] Uploaded ${uploaded} files, deleted ${deleted} stale files`);
879
879
  console.log("[qlara/aws] Bundling edge handler...");
880
880
  const edgeZip = await bundleEdgeHandler({
@@ -892,7 +892,8 @@ function aws(awsConfig = {}) {
892
892
  await lambda.send(
893
893
  new UpdateFunctionConfigurationCommand({
894
894
  FunctionName: res.edgeFunctionArn,
895
- Timeout: 30
895
+ Timeout: 30,
896
+ MemorySize: 512
896
897
  })
897
898
  );
898
899
  await waitUntilFunctionUpdatedV2(
@@ -979,7 +980,7 @@ function aws(awsConfig = {}) {
979
980
  new UpdateFunctionConfigurationCommand({
980
981
  FunctionName: res.rendererFunctionArn,
981
982
  Layers: [],
982
- MemorySize: 256,
983
+ MemorySize: 512,
983
984
  Timeout: 30,
984
985
  Environment: {
985
986
  Variables: config.env ?? {}
package/dist/cli.js CHANGED
@@ -77,12 +77,12 @@ function getContentType(filePath) {
77
77
  const ext = extname(filePath).toLowerCase();
78
78
  return CONTENT_TYPES[ext] || "application/octet-stream";
79
79
  }
80
- function getCacheControl(key) {
80
+ function getCacheControl(key, cacheTtl) {
81
81
  if (key.includes("_next/static/") || key.includes(".chunk.")) {
82
82
  return "public, max-age=31536000, immutable";
83
83
  }
84
84
  if (key.endsWith(".html")) {
85
- return "public, max-age=0, must-revalidate";
85
+ return `public, max-age=0, s-maxage=${cacheTtl}, stale-while-revalidate=60`;
86
86
  }
87
87
  return "public, max-age=86400";
88
88
  }
@@ -120,7 +120,7 @@ async function listAllKeys(client, bucketName) {
120
120
  } while (continuationToken);
121
121
  return keys;
122
122
  }
123
- async function syncToS3(client, bucketName, buildDir) {
123
+ async function syncToS3(client, bucketName, buildDir, cacheTtl = 3600) {
124
124
  const files = listFiles(buildDir);
125
125
  const newKeys = /* @__PURE__ */ new Set();
126
126
  let uploaded = 0;
@@ -133,7 +133,7 @@ async function syncToS3(client, bucketName, buildDir) {
133
133
  newKeys.add(key);
134
134
  const body = readFileSync(filePath);
135
135
  const contentType = getContentType(filePath);
136
- const cacheControl = getCacheControl(key);
136
+ const cacheControl = getCacheControl(key, cacheTtl);
137
137
  await client.send(
138
138
  new PutObjectCommand({
139
139
  Bucket: bucketName,
@@ -882,7 +882,7 @@ function aws(awsConfig = {}) {
882
882
  console.log(`[qlara/aws] Generated ${fallbacks.length} fallback page(s)`);
883
883
  console.log("[qlara/aws] Syncing build output to S3...");
884
884
  const s3 = createS3Client(res.region);
885
- const { uploaded, deleted } = await syncToS3(s3, res.bucketName, buildDir);
885
+ const { uploaded, deleted } = await syncToS3(s3, res.bucketName, buildDir, cacheTtl);
886
886
  console.log(`[qlara/aws] Uploaded ${uploaded} files, deleted ${deleted} stale files`);
887
887
  console.log("[qlara/aws] Bundling edge handler...");
888
888
  const edgeZip = await bundleEdgeHandler({
@@ -900,7 +900,8 @@ function aws(awsConfig = {}) {
900
900
  await lambda.send(
901
901
  new UpdateFunctionConfigurationCommand({
902
902
  FunctionName: res.edgeFunctionArn,
903
- Timeout: 30
903
+ Timeout: 30,
904
+ MemorySize: 512
904
905
  })
905
906
  );
906
907
  await waitUntilFunctionUpdatedV2(
@@ -987,7 +988,7 @@ function aws(awsConfig = {}) {
987
988
  new UpdateFunctionConfigurationCommand({
988
989
  FunctionName: res.rendererFunctionArn,
989
990
  Layers: [],
990
- MemorySize: 256,
991
+ MemorySize: 512,
991
992
  Timeout: 30,
992
993
  Environment: {
993
994
  Variables: config.env ?? {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qlara",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Runtime ISR for static React apps — dynamic routing and SEO metadata for statically exported Next.js apps on AWS",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -79,6 +79,9 @@ interface RendererResult {
79
79
 
80
80
  const FALLBACK_PLACEHOLDER = '__QLARA_FALLBACK__';
81
81
 
82
+ // Module-scope S3 client — reused across warm invocations (avoids recreating TCP/TLS connections)
83
+ const s3 = new S3Client({ region: process.env.AWS_REGION || 'us-east-1' });
84
+
82
85
  /**
83
86
  * Derive the S3 key for a rendered page.
84
87
  * Matches the Next.js static export convention: /product/42 → product/42.html
@@ -763,9 +766,6 @@ export async function handler(event: RendererEvent & { warmup?: boolean }): Prom
763
766
  }
764
767
 
765
768
  const { uri, bucket, routePattern, params } = event;
766
- const region = process.env.AWS_REGION || 'us-east-1';
767
-
768
- const s3 = new S3Client({ region });
769
769
 
770
770
  try {
771
771
  // 0. Check if already rendered + read fallback in parallel