effortless-aws 0.1.1 → 0.2.0

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.
@@ -99,6 +99,21 @@ var createTableClient = (tableName) => {
99
99
  };
100
100
  };
101
101
 
102
+ // src/runtime/platform-types.ts
103
+ var ENV_PLATFORM_TABLE = "EFF_PLATFORM_TABLE";
104
+ var DEFAULT_TTL_SECONDS = 7 * 24 * 60 * 60;
105
+ var truncateForStorage = (value, maxLength = 4096) => {
106
+ if (value === void 0 || value === null) return value;
107
+ const str = typeof value === "string" ? value : JSON.stringify(value);
108
+ if (str.length <= maxLength) return value;
109
+ return str.slice(0, maxLength) + "...[truncated]";
110
+ };
111
+ var dateBucket = (date = /* @__PURE__ */ new Date()) => date.toISOString().slice(0, 10);
112
+ var computeTtl = (ttlSeconds = DEFAULT_TTL_SECONDS) => Math.floor(Date.now() / 1e3) + ttlSeconds;
113
+
114
+ // src/runtime/handler-utils.ts
115
+ import { randomUUID } from "crypto";
116
+
102
117
  // src/runtime/ssm-client.ts
103
118
  import { SSM } from "@aws-sdk/client-ssm";
104
119
  var client = null;
@@ -120,6 +135,89 @@ var getParameters = async (names) => {
120
135
  return map;
121
136
  };
122
137
 
138
+ // src/runtime/platform-client.ts
139
+ import { DynamoDB as DynamoDB2 } from "@aws-sdk/client-dynamodb";
140
+ import { marshall as marshall2, unmarshall as unmarshall2 } from "@aws-sdk/util-dynamodb";
141
+ var createPlatformClient = () => {
142
+ const tableName = process.env[ENV_PLATFORM_TABLE];
143
+ if (!tableName) return void 0;
144
+ let client2 = null;
145
+ const getClient2 = () => client2 ??= new DynamoDB2({});
146
+ const appendToList = async (handlerName, handlerType, listAttr, entry) => {
147
+ const sk = `EXEC#${dateBucket()}`;
148
+ try {
149
+ await getClient2().updateItem({
150
+ TableName: tableName,
151
+ Key: marshall2({ pk: `HANDLER#${handlerName}`, sk }),
152
+ UpdateExpression: "SET #list = list_append(if_not_exists(#list, :empty), :entry), #type = :type, #hn = :hn, #ht = :ht, #ttl = :ttl",
153
+ ExpressionAttributeNames: {
154
+ "#list": listAttr,
155
+ "#type": "type",
156
+ "#hn": "handlerName",
157
+ "#ht": "handlerType",
158
+ "#ttl": "ttl"
159
+ },
160
+ ExpressionAttributeValues: marshall2(
161
+ {
162
+ ":entry": [entry],
163
+ ":empty": [],
164
+ ":type": "execution-log",
165
+ ":hn": handlerName,
166
+ ":ht": handlerType,
167
+ ":ttl": computeTtl()
168
+ },
169
+ { removeUndefinedValues: true }
170
+ )
171
+ });
172
+ } catch (err) {
173
+ console.error("[effortless] Failed to write platform record:", err);
174
+ }
175
+ };
176
+ return {
177
+ tableName,
178
+ async appendExecution(handlerName, handlerType, entry) {
179
+ await appendToList(handlerName, handlerType, "executions", entry);
180
+ },
181
+ async appendError(handlerName, handlerType, entry) {
182
+ await appendToList(handlerName, handlerType, "errors", entry);
183
+ },
184
+ async get(pk, sk) {
185
+ const result = await getClient2().getItem({
186
+ TableName: tableName,
187
+ Key: marshall2({ pk, sk })
188
+ });
189
+ return result.Item ? unmarshall2(result.Item) : void 0;
190
+ },
191
+ async query(pk, skPrefix) {
192
+ const names = { "#pk": "pk" };
193
+ const values = { ":pk": pk };
194
+ let keyCondition = "#pk = :pk";
195
+ if (skPrefix) {
196
+ names["#sk"] = "sk";
197
+ values[":sk"] = skPrefix;
198
+ keyCondition += " AND begins_with(#sk, :sk)";
199
+ }
200
+ const result = await getClient2().query({
201
+ TableName: tableName,
202
+ KeyConditionExpression: keyCondition,
203
+ ExpressionAttributeNames: names,
204
+ ExpressionAttributeValues: marshall2(values, { removeUndefinedValues: true })
205
+ });
206
+ return (result.Items ?? []).map((item) => unmarshall2(item));
207
+ },
208
+ async put(entity) {
209
+ try {
210
+ await getClient2().putItem({
211
+ TableName: tableName,
212
+ Item: marshall2(entity, { removeUndefinedValues: true })
213
+ });
214
+ } catch (err) {
215
+ console.error("[effortless] Failed to write platform record:", err);
216
+ }
217
+ }
218
+ };
219
+ };
220
+
123
221
  // src/runtime/handler-utils.ts
124
222
  var ENV_TABLE_PREFIX = "EFF_TABLE_";
125
223
  var ENV_PARAM_PREFIX = "EFF_PARAM_";
@@ -155,9 +253,58 @@ var buildParams = async (params) => {
155
253
  }
156
254
  return result;
157
255
  };
256
+ var createHandlerRuntime = (handler, handlerType) => {
257
+ const platform = createPlatformClient();
258
+ const handlerName = process.env.EFF_HANDLER ?? "unknown";
259
+ let ctx = null;
260
+ let resolvedDeps;
261
+ let resolvedParams = null;
262
+ const getDeps = () => resolvedDeps ??= buildDeps(handler.deps);
263
+ const getParams = async () => {
264
+ if (resolvedParams !== null) return resolvedParams;
265
+ resolvedParams = await buildParams(handler.params);
266
+ return resolvedParams;
267
+ };
268
+ const getCtx = async () => {
269
+ if (ctx !== null) return ctx;
270
+ if (handler.context) {
271
+ const params = await getParams();
272
+ ctx = params ? await handler.context({ params }) : await handler.context();
273
+ }
274
+ return ctx;
275
+ };
276
+ const commonArgs = async () => {
277
+ const args = {};
278
+ if (handler.context) args.ctx = await getCtx();
279
+ const deps = getDeps();
280
+ if (deps) args.deps = deps;
281
+ const params = await getParams();
282
+ if (params) args.params = params;
283
+ return args;
284
+ };
285
+ const logExecution = (startTime, input, output) => {
286
+ platform?.appendExecution(handlerName, handlerType, {
287
+ id: randomUUID(),
288
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
289
+ ms: Date.now() - startTime,
290
+ in: input,
291
+ out: truncateForStorage(output)
292
+ });
293
+ };
294
+ const logError = (startTime, input, error) => {
295
+ platform?.appendError(handlerName, handlerType, {
296
+ id: randomUUID(),
297
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
298
+ ms: Date.now() - startTime,
299
+ in: input,
300
+ err: error instanceof Error ? error.message : String(error)
301
+ });
302
+ };
303
+ return { commonArgs, logExecution, logError, handlerName };
304
+ };
158
305
 
159
306
  export {
160
307
  createTableClient,
161
- buildDeps,
162
- buildParams
308
+ truncateForStorage,
309
+ createHandlerRuntime
163
310
  };
package/dist/cli/index.js CHANGED
@@ -69937,15 +69937,39 @@ var waitForTableActive = (tableName) => Effect_exports.gen(function* () {
69937
69937
  }
69938
69938
  return yield* Effect_exports.fail(new Error(`Timeout waiting for table ${tableName} to become active`));
69939
69939
  });
69940
+ var ensureTimeToLive = (tableName, attributeName) => Effect_exports.gen(function* () {
69941
+ const current = yield* dynamodb_exports.make("describe_time_to_live", {
69942
+ TableName: tableName
69943
+ });
69944
+ const status2 = current.TimeToLiveDescription?.TimeToLiveStatus;
69945
+ const currentAttr = current.TimeToLiveDescription?.AttributeName;
69946
+ if (status2 === "ENABLED" && currentAttr === attributeName) {
69947
+ return;
69948
+ }
69949
+ if (status2 === "ENABLING") {
69950
+ yield* Effect_exports.logInfo(`TTL is being enabled on ${tableName}, waiting...`);
69951
+ yield* Effect_exports.sleep(5e3);
69952
+ return;
69953
+ }
69954
+ yield* Effect_exports.logInfo(`Enabling TTL on ${tableName} (attribute: ${attributeName})`);
69955
+ yield* dynamodb_exports.make("update_time_to_live", {
69956
+ TableName: tableName,
69957
+ TimeToLiveSpecification: {
69958
+ Enabled: true,
69959
+ AttributeName: attributeName
69960
+ }
69961
+ });
69962
+ });
69940
69963
  var ensureTable = (input) => Effect_exports.gen(function* () {
69941
- const { name, pk, sk, billingMode = "PAY_PER_REQUEST", streamView = "NEW_AND_OLD_IMAGES", tags: tags2 } = input;
69964
+ const { name, pk, sk, billingMode = "PAY_PER_REQUEST", streamView = "NEW_AND_OLD_IMAGES", tags: tags2, ttlAttribute } = input;
69942
69965
  const existingTable = yield* dynamodb_exports.make("describe_table", { TableName: name }).pipe(
69943
- Effect_exports.map((result) => result.Table),
69966
+ Effect_exports.map((result2) => result2.Table),
69944
69967
  Effect_exports.catchIf(
69945
69968
  (error4) => error4 instanceof dynamodb_exports.DynamoDBError && error4.cause.name === "ResourceNotFoundException",
69946
69969
  () => Effect_exports.succeed(void 0)
69947
69970
  )
69948
69971
  );
69972
+ let result;
69949
69973
  if (!existingTable) {
69950
69974
  yield* Effect_exports.logInfo(`Creating table ${name}...`);
69951
69975
  const keySchema = [
@@ -69967,34 +69991,40 @@ var ensureTable = (input) => Effect_exports.gen(function* () {
69967
69991
  Tags: tags2 ? toAwsTagList(tags2) : void 0
69968
69992
  });
69969
69993
  const table3 = yield* waitForTableActive(name);
69970
- return {
69994
+ result = {
69971
69995
  tableArn: table3.TableArn,
69972
69996
  streamArn: table3.LatestStreamArn
69973
69997
  };
69998
+ } else {
69999
+ yield* Effect_exports.logInfo(`Table ${name} already exists`);
70000
+ if (tags2) {
70001
+ yield* dynamodb_exports.make("tag_resource", {
70002
+ ResourceArn: existingTable.TableArn,
70003
+ Tags: toAwsTagList(tags2)
70004
+ });
70005
+ }
70006
+ if (!existingTable.StreamSpecification?.StreamEnabled) {
70007
+ yield* Effect_exports.logInfo(`Enabling stream on table ${name}...`);
70008
+ yield* dynamodb_exports.make("update_table", {
70009
+ TableName: name,
70010
+ StreamSpecification: streamViewToSpec(streamView)
70011
+ });
70012
+ const table3 = yield* waitForTableActive(name);
70013
+ result = {
70014
+ tableArn: table3.TableArn,
70015
+ streamArn: table3.LatestStreamArn
70016
+ };
70017
+ } else {
70018
+ result = {
70019
+ tableArn: existingTable.TableArn,
70020
+ streamArn: existingTable.LatestStreamArn
70021
+ };
70022
+ }
69974
70023
  }
69975
- yield* Effect_exports.logInfo(`Table ${name} already exists`);
69976
- if (tags2) {
69977
- yield* dynamodb_exports.make("tag_resource", {
69978
- ResourceArn: existingTable.TableArn,
69979
- Tags: toAwsTagList(tags2)
69980
- });
69981
- }
69982
- if (!existingTable.StreamSpecification?.StreamEnabled) {
69983
- yield* Effect_exports.logInfo(`Enabling stream on table ${name}...`);
69984
- yield* dynamodb_exports.make("update_table", {
69985
- TableName: name,
69986
- StreamSpecification: streamViewToSpec(streamView)
69987
- });
69988
- const table3 = yield* waitForTableActive(name);
69989
- return {
69990
- tableArn: table3.TableArn,
69991
- streamArn: table3.LatestStreamArn
69992
- };
70024
+ if (ttlAttribute) {
70025
+ yield* ensureTimeToLive(name, ttlAttribute);
69993
70026
  }
69994
- return {
69995
- tableArn: existingTable.TableArn,
69996
- streamArn: existingTable.LatestStreamArn
69997
- };
70027
+ return result;
69998
70028
  });
69999
70029
  var ensureEventSourceMapping = (input) => Effect_exports.gen(function* () {
70000
70030
  const { functionArn, streamArn, batchSize = 100, batchWindow, startingPosition = "LATEST" } = input;
@@ -70162,10 +70192,10 @@ var computeLockfileHash = (projectDir) => Effect_exports.gen(function* () {
70162
70192
  if (prodDeps.length === 0) {
70163
70193
  return yield* Effect_exports.fail(new Error("No production dependencies"));
70164
70194
  }
70165
- const { packages: allPackages } = collectTransitiveDeps(projectDir, prodDeps);
70195
+ const { packages: allPackages, resolvedPaths } = collectTransitiveDeps(projectDir, prodDeps);
70166
70196
  const packageVersions = [];
70167
70197
  for (const pkgName of Array.from(allPackages).sort()) {
70168
- const pkgPath = findInPnpmStore(projectDir, pkgName) ?? getPackageRealPath(projectDir, pkgName);
70198
+ const pkgPath = resolvedPaths.get(pkgName) ?? findInPnpmStore(projectDir, pkgName) ?? getPackageRealPath(projectDir, pkgName);
70169
70199
  if (pkgPath) {
70170
70200
  const version = getPackageVersion(pkgPath);
70171
70201
  if (version) {
@@ -70231,7 +70261,7 @@ var findInPnpmStore = (projectDir, pkgName) => {
70231
70261
  }
70232
70262
  return null;
70233
70263
  };
70234
- var collectTransitiveDeps = (projectDir, rootDeps, searchPath = path4.join(projectDir, "node_modules"), visited = /* @__PURE__ */ new Set(), warnings = []) => {
70264
+ var collectTransitiveDeps = (projectDir, rootDeps, searchPath = path4.join(projectDir, "node_modules"), visited = /* @__PURE__ */ new Set(), resolvedPaths = /* @__PURE__ */ new Map(), warnings = []) => {
70235
70265
  const rootNodeModules = path4.join(projectDir, "node_modules");
70236
70266
  for (const dep of rootDeps) {
70237
70267
  if (visited.has(dep)) continue;
@@ -70262,44 +70292,63 @@ var collectTransitiveDeps = (projectDir, rootDeps, searchPath = path4.join(proje
70262
70292
  continue;
70263
70293
  }
70264
70294
  visited.add(dep);
70295
+ resolvedPaths.set(dep, realPath2);
70265
70296
  const pkgDeps = getPackageDeps(realPath2);
70266
70297
  if (pkgDeps.length > 0) {
70267
70298
  const isScoped = dep.startsWith("@");
70268
70299
  const pkgNodeModules = isScoped ? path4.dirname(path4.dirname(realPath2)) : path4.dirname(realPath2);
70269
- collectTransitiveDeps(projectDir, pkgDeps, pkgNodeModules, visited, warnings);
70300
+ collectTransitiveDeps(projectDir, pkgDeps, pkgNodeModules, visited, resolvedPaths, warnings);
70270
70301
  }
70271
70302
  }
70272
- return { packages: visited, warnings };
70303
+ return { packages: visited, resolvedPaths, warnings };
70273
70304
  };
70274
70305
  var isAwsRuntime = (pkg) => pkg.startsWith("@aws-sdk/") || pkg.startsWith("@smithy/");
70275
70306
  var collectLayerPackages = (projectDir, dependencies) => {
70276
- if (dependencies.length === 0) return { packages: [], warnings: [] };
70277
- const { packages, warnings } = collectTransitiveDeps(projectDir, dependencies);
70307
+ if (dependencies.length === 0) return { packages: [], resolvedPaths: /* @__PURE__ */ new Map(), warnings: [] };
70308
+ const { packages, resolvedPaths, warnings } = collectTransitiveDeps(projectDir, dependencies);
70278
70309
  let changed = true;
70279
70310
  while (changed) {
70280
70311
  changed = false;
70281
70312
  for (const pkg of [...packages]) {
70282
70313
  if (isAwsRuntime(pkg)) continue;
70283
- const pkgPath = findPackagePath(projectDir, pkg);
70284
- if (!pkgPath) continue;
70285
- const pkgDeps = getPackageDeps(pkgPath);
70286
- for (const dep of pkgDeps) {
70287
- if (!packages.has(dep) && !isAwsRuntime(dep)) {
70288
- packages.add(dep);
70289
- warnings.push(`Auto-added missing transitive dep: "${dep}" (required by "${pkg}")`);
70290
- changed = true;
70314
+ const pkgPaths = /* @__PURE__ */ new Set();
70315
+ const resolved = resolvedPaths.get(pkg);
70316
+ if (resolved) pkgPaths.add(resolved);
70317
+ const found = findPackagePath(projectDir, pkg);
70318
+ if (found) pkgPaths.add(found);
70319
+ if (pkgPaths.size === 0) continue;
70320
+ for (const pkgPath of pkgPaths) {
70321
+ const pkgDeps = getPackageDeps(pkgPath);
70322
+ for (const dep of pkgDeps) {
70323
+ if (!packages.has(dep) && !isAwsRuntime(dep)) {
70324
+ packages.add(dep);
70325
+ changed = true;
70326
+ let depPath = findPackagePath(projectDir, dep);
70327
+ if (!depPath) {
70328
+ const isScoped = pkg.startsWith("@");
70329
+ const parentNodeModules = isScoped ? path4.dirname(path4.dirname(pkgPath)) : path4.dirname(pkgPath);
70330
+ const depInParent = path4.join(parentNodeModules, dep);
70331
+ if (fsSync.existsSync(depInParent)) {
70332
+ try {
70333
+ depPath = fsSync.realpathSync(depInParent);
70334
+ } catch {
70335
+ }
70336
+ }
70337
+ }
70338
+ if (depPath) resolvedPaths.set(dep, depPath);
70339
+ }
70291
70340
  }
70292
70341
  }
70293
70342
  }
70294
70343
  }
70295
- return { packages: Array.from(packages), warnings };
70344
+ return { packages: Array.from(packages), resolvedPaths, warnings };
70296
70345
  };
70297
70346
  var findPackagePath = (projectDir, pkgName) => {
70298
70347
  const rootPath = getPackageRealPath(projectDir, pkgName);
70299
70348
  if (rootPath) return rootPath;
70300
70349
  return findInPnpmStore(projectDir, pkgName);
70301
70350
  };
70302
- var createLayerZip = (projectDir, packages) => Effect_exports.async((resume2) => {
70351
+ var createLayerZip = (projectDir, packages, resolvedPaths) => Effect_exports.async((resume2) => {
70303
70352
  const chunks2 = [];
70304
70353
  const archive = archiver("zip", { zlib: { level: 9 } });
70305
70354
  const addedPaths = /* @__PURE__ */ new Set();
@@ -70313,7 +70362,7 @@ var createLayerZip = (projectDir, packages) => Effect_exports.async((resume2) =>
70313
70362
  })));
70314
70363
  archive.on("error", (err) => resume2(Effect_exports.fail(err)));
70315
70364
  for (const pkgName of packages) {
70316
- const realPath2 = findPackagePath(projectDir, pkgName);
70365
+ const realPath2 = resolvedPaths?.get(pkgName) ?? findPackagePath(projectDir, pkgName);
70317
70366
  if (typeof realPath2 === "string" && realPath2.length > 0 && !addedPaths.has(realPath2)) {
70318
70367
  addedPaths.add(realPath2);
70319
70368
  includedPackages.push(pkgName);
@@ -70371,13 +70420,13 @@ var ensureLayer = (config2) => Effect_exports.gen(function* () {
70371
70420
  yield* Effect_exports.logInfo(`Layer ${layerName} with hash ${hash2} already exists (version ${existing.version})`);
70372
70421
  return existing;
70373
70422
  }
70374
- const { packages: allPackages, warnings: layerWarnings } = yield* Effect_exports.sync(() => collectLayerPackages(config2.projectDir, dependencies));
70423
+ const { packages: allPackages, resolvedPaths, warnings: layerWarnings } = yield* Effect_exports.sync(() => collectLayerPackages(config2.projectDir, dependencies));
70375
70424
  for (const warning of layerWarnings) {
70376
70425
  yield* Effect_exports.logWarning(`[layer] ${warning}`);
70377
70426
  }
70378
70427
  yield* Effect_exports.logInfo(`Creating layer ${layerName} with ${allPackages.length} packages (hash: ${hash2})`);
70379
70428
  yield* Effect_exports.logDebug(`Layer packages: ${allPackages.join(", ")}`);
70380
- const { buffer: layerZip, includedPackages, skippedPackages } = yield* createLayerZip(config2.projectDir, allPackages);
70429
+ const { buffer: layerZip, includedPackages, skippedPackages } = yield* createLayerZip(config2.projectDir, allPackages, resolvedPaths);
70381
70430
  if (skippedPackages.length > 0) {
70382
70431
  yield* Effect_exports.logWarning(`Skipped ${skippedPackages.length} packages (not found): ${skippedPackages.slice(0, 10).join(", ")}${skippedPackages.length > 10 ? "..." : ""}`);
70383
70432
  }
@@ -71083,6 +71132,31 @@ var mergeResolved = (deps, params) => {
71083
71132
  if (Object.keys(env2).length === 0) return void 0;
71084
71133
  return { depsEnv: env2, depsPermissions: permissions };
71085
71134
  };
71135
+ var PLATFORM_PERMISSIONS = [
71136
+ "dynamodb:PutItem",
71137
+ "dynamodb:GetItem",
71138
+ "dynamodb:UpdateItem",
71139
+ "dynamodb:Query"
71140
+ ];
71141
+ var ensurePlatformTable = (project2, stage, region) => Effect_exports.gen(function* () {
71142
+ const tableName = `${project2}-${stage}-platform`;
71143
+ const tagCtx = { project: project2, stage, handler: "platform" };
71144
+ yield* Effect_exports.logInfo(`Ensuring platform table: ${tableName}`);
71145
+ yield* ensureTable({
71146
+ name: tableName,
71147
+ pk: { name: "pk", type: "string" },
71148
+ sk: { name: "sk", type: "string" },
71149
+ billingMode: "PAY_PER_REQUEST",
71150
+ streamView: "NEW_AND_OLD_IMAGES",
71151
+ tags: makeTags(tagCtx, "dynamodb"),
71152
+ ttlAttribute: "ttl"
71153
+ }).pipe(
71154
+ Effect_exports.provide(
71155
+ clients_exports.makeClients({ dynamodb: { region } })
71156
+ )
71157
+ );
71158
+ return tableName;
71159
+ });
71086
71160
  var deployHttpHandlers = (ctx) => Effect_exports.gen(function* () {
71087
71161
  const results = [];
71088
71162
  for (const { file: file6, exports } of ctx.handlers) {
@@ -71100,12 +71174,17 @@ var deployHttpHandlers = (ctx) => Effect_exports.gen(function* () {
71100
71174
  resolveDeps(fn2.depsKeys, ctx.tableNameMap),
71101
71175
  resolveParams(fn2.paramEntries, ctx.input.project, stage)
71102
71176
  );
71177
+ const withPlatform = {
71178
+ depsEnv: { ...resolved?.depsEnv, ...ctx.platformEnv },
71179
+ depsPermissions: [...resolved?.depsPermissions ?? [], ...ctx.platformPermissions]
71180
+ };
71103
71181
  const { exportName, functionArn, config: config2 } = yield* deployLambda({
71104
71182
  input: deployInput,
71105
71183
  fn: fn2,
71106
71184
  ...ctx.layerArn ? { layerArn: ctx.layerArn } : {},
71107
71185
  ...ctx.external.length > 0 ? { external: ctx.external } : {},
71108
- ...resolved ? { depsEnv: resolved.depsEnv, depsPermissions: resolved.depsPermissions } : {}
71186
+ depsEnv: withPlatform.depsEnv,
71187
+ depsPermissions: withPlatform.depsPermissions
71109
71188
  }).pipe(
71110
71189
  Effect_exports.provide(
71111
71190
  clients_exports.makeClients({
@@ -71151,12 +71230,17 @@ var deployTableHandlers = (ctx) => Effect_exports.gen(function* () {
71151
71230
  resolveDeps(fn2.depsKeys, ctx.tableNameMap),
71152
71231
  resolveParams(fn2.paramEntries, ctx.input.project, stage)
71153
71232
  );
71233
+ const withPlatform = {
71234
+ depsEnv: { ...resolved?.depsEnv, ...ctx.platformEnv },
71235
+ depsPermissions: [...resolved?.depsPermissions ?? [], ...ctx.platformPermissions]
71236
+ };
71154
71237
  const result = yield* deployTableFunction({
71155
71238
  input: deployInput,
71156
71239
  fn: fn2,
71157
71240
  ...ctx.layerArn ? { layerArn: ctx.layerArn } : {},
71158
71241
  ...ctx.external.length > 0 ? { external: ctx.external } : {},
71159
- ...resolved ? { depsEnv: resolved.depsEnv, depsPermissions: resolved.depsPermissions } : {}
71242
+ depsEnv: withPlatform.depsEnv,
71243
+ depsPermissions: withPlatform.depsPermissions
71160
71244
  }).pipe(
71161
71245
  Effect_exports.provide(
71162
71246
  clients_exports.makeClients({
@@ -71191,6 +71275,9 @@ var deployProject = (input) => Effect_exports.gen(function* () {
71191
71275
  region: input.region,
71192
71276
  projectDir: input.projectDir
71193
71277
  });
71278
+ const stage = resolveStage(input.stage);
71279
+ const platformTableName = yield* ensurePlatformTable(input.project, stage, input.region);
71280
+ const platformEnv = { EFF_PLATFORM_TABLE: platformTableName };
71194
71281
  let apiId;
71195
71282
  let apiUrl;
71196
71283
  if (totalHttpHandlers > 0) {
@@ -71221,14 +71308,18 @@ var deployProject = (input) => Effect_exports.gen(function* () {
71221
71308
  input,
71222
71309
  layerArn,
71223
71310
  external,
71224
- tableNameMap
71311
+ tableNameMap,
71312
+ platformEnv,
71313
+ platformPermissions: PLATFORM_PERMISSIONS
71225
71314
  }) : [];
71226
71315
  const tableResults = yield* deployTableHandlers({
71227
71316
  handlers: tableHandlers,
71228
71317
  input,
71229
71318
  layerArn,
71230
71319
  external,
71231
- tableNameMap
71320
+ tableNameMap,
71321
+ platformEnv,
71322
+ platformPermissions: PLATFORM_PERMISSIONS
71232
71323
  });
71233
71324
  if (apiUrl) {
71234
71325
  yield* Effect_exports.logInfo(`Deployment complete! API: ${apiUrl}`);
@@ -72105,31 +72196,6 @@ Deleted ${deleted} layer version(s).`);
72105
72196
  );
72106
72197
  })
72107
72198
  ).pipe(Command_exports.withDescription("Delete layer versions"));
72108
- var findPackagePathForCopy = (projectDir, pkgName) => {
72109
- const rootPath = path11.join(projectDir, "node_modules", pkgName);
72110
- if (fs5.existsSync(rootPath)) {
72111
- try {
72112
- return fs5.realpathSync(rootPath);
72113
- } catch {
72114
- }
72115
- }
72116
- const pnpmDir = path11.join(projectDir, "node_modules", ".pnpm");
72117
- if (!fs5.existsSync(pnpmDir)) return null;
72118
- const pnpmPkgName = pkgName.replace("/", "+");
72119
- try {
72120
- const entries2 = fs5.readdirSync(pnpmDir);
72121
- for (const entry of entries2) {
72122
- if (entry.startsWith(pnpmPkgName + "@")) {
72123
- const pkgPath = path11.join(pnpmDir, entry, "node_modules", pkgName);
72124
- if (fs5.existsSync(pkgPath)) {
72125
- return fs5.realpathSync(pkgPath);
72126
- }
72127
- }
72128
- }
72129
- } catch {
72130
- }
72131
- return null;
72132
- };
72133
72199
  var layersBuildCommand = Command_exports.make(
72134
72200
  "build",
72135
72201
  { output: outputOption, verbose: verboseOption },
@@ -72160,7 +72226,7 @@ var layersBuildCommand = Command_exports.make(
72160
72226
  );
72161
72227
  yield* Console_exports.log(`
72162
72228
  Lockfile hash: ${hash2}`);
72163
- const { packages: allPackages, warnings: layerWarnings } = yield* Effect_exports.sync(() => collectLayerPackages(projectDir, prodDeps));
72229
+ const { packages: allPackages, resolvedPaths, warnings: layerWarnings } = yield* Effect_exports.sync(() => collectLayerPackages(projectDir, prodDeps));
72164
72230
  if (layerWarnings.length > 0) {
72165
72231
  yield* Console_exports.log(`
72166
72232
  Warnings (${layerWarnings.length}):`);
@@ -72179,7 +72245,7 @@ Collected ${allPackages.length} packages for layer`);
72179
72245
  let copied = 0;
72180
72246
  let skipped = 0;
72181
72247
  for (const pkgName of allPackages) {
72182
- const srcPath = findPackagePathForCopy(projectDir, pkgName);
72248
+ const srcPath = resolvedPaths.get(pkgName) ?? null;
72183
72249
  if (!srcPath) {
72184
72250
  skipped++;
72185
72251
  if (verbose) {