@awsless/cli 0.0.46-local.44 → 0.0.46-local.46

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/bin.js CHANGED
@@ -152670,10 +152670,290 @@ class TypeObject {
152670
152670
  }
152671
152671
  }
152672
152672
 
152673
+ // src/feature/auth/dev.ts
152674
+ import {
152675
+ AdminAddUserToGroupCommand,
152676
+ AdminCreateUserCommand,
152677
+ AdminGetUserCommand,
152678
+ AdminListGroupsForUserCommand,
152679
+ AdminRemoveUserFromGroupCommand,
152680
+ AdminSetUserPasswordCommand,
152681
+ CognitoIdentityProviderClient,
152682
+ ListUserPoolClientsCommand,
152683
+ ListUserPoolsCommand,
152684
+ ListUsersCommand,
152685
+ UserNotFoundException,
152686
+ UsernameExistsException
152687
+ } from "@aws-sdk/client-cognito-identity-provider";
152688
+ var authOnDev = async (ctx) => {
152689
+ const ids = Object.keys(ctx.appConfig.auth ?? {});
152690
+ if (ids.length === 0) {
152691
+ return;
152692
+ }
152693
+ const pools = await ctx.keep("auth:pull", [...ids].sort().join(","), async () => {
152694
+ const values = {};
152695
+ try {
152696
+ ctx.log(`Resolving ${ids.length} auth userpool${ids.length === 1 ? "" : "s"} from Cognito...`);
152697
+ const credentials2 = await getCredentials(ctx.appConfig.profile);
152698
+ const client = new CognitoIdentityProviderClient({
152699
+ region: ctx.appConfig.region,
152700
+ credentials: credentials2
152701
+ });
152702
+ let timer;
152703
+ const timeout = new Promise((_3, reject) => {
152704
+ timer = setTimeout(() => reject(new Error("the lookup timed out after 15s")), 15000);
152705
+ });
152706
+ const resolve2 = async () => {
152707
+ const poolIdsByName = {};
152708
+ let token;
152709
+ do {
152710
+ const result = await client.send(new ListUserPoolsCommand({
152711
+ MaxResults: 60,
152712
+ NextToken: token
152713
+ }));
152714
+ for (const pool of result.UserPools ?? []) {
152715
+ if (pool.Name && pool.Id) {
152716
+ poolIdsByName[pool.Name] = pool.Id;
152717
+ }
152718
+ }
152719
+ token = result.NextToken;
152720
+ } while (token);
152721
+ for (const id of ids) {
152722
+ const name = formatGlobalResourceName({
152723
+ appName: ctx.appConfig.name,
152724
+ resourceType: "auth",
152725
+ resourceName: id
152726
+ });
152727
+ const userPoolId = poolIdsByName[name];
152728
+ if (!userPoolId) {
152729
+ ctx.log(`The auth userpool "${id}" isn't deployed yet - its login won't work locally.`);
152730
+ continue;
152731
+ }
152732
+ const clients = await client.send(new ListUserPoolClientsCommand({
152733
+ UserPoolId: userPoolId,
152734
+ MaxResults: 60
152735
+ }));
152736
+ const appClient = clients.UserPoolClients?.find((client2) => client2.ClientName === name) ?? clients.UserPoolClients?.[0];
152737
+ if (!appClient?.ClientId) {
152738
+ ctx.log(`The auth userpool "${id}" has no client - its login won't work locally.`);
152739
+ continue;
152740
+ }
152741
+ values[id] = {
152742
+ userPoolId,
152743
+ clientId: appClient.ClientId
152744
+ };
152745
+ }
152746
+ };
152747
+ await Promise.race([resolve2(), timeout]).finally(() => clearTimeout(timer));
152748
+ } catch (error3) {
152749
+ debug("Auth userpool lookup failed", error3);
152750
+ ctx.log(`Couldn't resolve the auth userpools from Cognito (${error3 instanceof Error ? error3.message : String(error3)}) - logins won't work locally.`);
152751
+ }
152752
+ return { value: values, stop: () => {} };
152753
+ });
152754
+ for (const [id, pool] of Object.entries(pools)) {
152755
+ ctx.addEnv(`AUTH_${constantCase(id)}_USER_POOL_ID`, pool.userPoolId);
152756
+ ctx.addEnv(`AUTH_${constantCase(id)}_CLIENT_ID`, pool.clientId);
152757
+ }
152758
+ for (const id of ids) {
152759
+ ctx.registerResource({
152760
+ kind: "auth",
152761
+ id,
152762
+ detail: pools[id]?.userPoolId ?? "not deployed"
152763
+ });
152764
+ }
152765
+ };
152766
+ var createAuthAdmin = (props) => {
152767
+ let client;
152768
+ const getClient = async () => {
152769
+ client ??= new CognitoIdentityProviderClient({
152770
+ region: props.appConfig.region,
152771
+ credentials: await getCredentials(props.appConfig.profile)
152772
+ });
152773
+ return client;
152774
+ };
152775
+ const getPool = (id) => {
152776
+ const authProps = props.appConfig.auth?.[id];
152777
+ const resolved = props.resolvedPools()?.[id];
152778
+ if (!authProps) {
152779
+ throw new Error(`The auth userpool "${id}" doesn't exist.`);
152780
+ }
152781
+ if (!resolved) {
152782
+ throw new Error(`The auth userpool "${id}" isn't deployed yet.`);
152783
+ }
152784
+ return { ...authProps, userPoolId: resolved.userPoolId };
152785
+ };
152786
+ const validatePassword = (pool, value) => {
152787
+ if (!value) {
152788
+ return "A password is required";
152789
+ }
152790
+ if (value.length < pool.password.minLength) {
152791
+ return `The password min length is ${pool.password.minLength}`;
152792
+ }
152793
+ if (pool.password.lowercase && value.toUpperCase() === value) {
152794
+ return `The password should include lowercase characters`;
152795
+ }
152796
+ if (pool.password.uppercase && value.toLowerCase() === value) {
152797
+ return `The password should include uppercase characters`;
152798
+ }
152799
+ if (pool.password.numbers && !/\d/.test(value)) {
152800
+ return `The password should include numbers`;
152801
+ }
152802
+ if (pool.password.symbols && !/[ `!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/.test(value)) {
152803
+ return `The password should include symbols`;
152804
+ }
152805
+ return;
152806
+ };
152807
+ const validateGroups = (pool, groups) => {
152808
+ for (const group4 of groups) {
152809
+ if (!pool.groups.includes(group4)) {
152810
+ throw new Error(`The group "${group4}" doesn't exist.`);
152811
+ }
152812
+ }
152813
+ };
152814
+ const listUserGroups = async (userPoolId, username) => {
152815
+ const client2 = await getClient();
152816
+ const groups = [];
152817
+ let token;
152818
+ do {
152819
+ const result = await client2.send(new AdminListGroupsForUserCommand({
152820
+ UserPoolId: userPoolId,
152821
+ Username: username,
152822
+ NextToken: token
152823
+ }));
152824
+ groups.push(...result.Groups?.map((group4) => group4.GroupName) ?? []);
152825
+ token = result.NextToken;
152826
+ } while (token);
152827
+ return groups;
152828
+ };
152829
+ return {
152830
+ describePool(id) {
152831
+ const pool = getPool(id);
152832
+ return {
152833
+ groups: pool.groups,
152834
+ password: pool.password
152835
+ };
152836
+ },
152837
+ async listUsers(id) {
152838
+ const pool = getPool(id);
152839
+ const client2 = await getClient();
152840
+ const users = [];
152841
+ let token;
152842
+ do {
152843
+ const result = await client2.send(new ListUsersCommand({
152844
+ UserPoolId: pool.userPoolId,
152845
+ PaginationToken: token
152846
+ }));
152847
+ for (const user of result.Users ?? []) {
152848
+ users.push({
152849
+ username: user.Username,
152850
+ email: user.Attributes?.find((a3) => a3.Name === "email")?.Value,
152851
+ status: user.UserStatus,
152852
+ enabled: user.Enabled ?? true,
152853
+ createdAt: user.UserCreateDate?.toISOString(),
152854
+ groups: []
152855
+ });
152856
+ }
152857
+ token = result.PaginationToken;
152858
+ } while (token && users.length < 500);
152859
+ await Promise.all(users.map(async (user) => {
152860
+ user.groups = await listUserGroups(pool.userPoolId, user.username);
152861
+ }));
152862
+ return users.sort((a3, b5) => a3.username.localeCompare(b5.username));
152863
+ },
152864
+ async createUser(id, input) {
152865
+ const pool = getPool(id);
152866
+ if (!input.username) {
152867
+ throw new Error("A username is required");
152868
+ }
152869
+ const issue = validatePassword(pool, input.password);
152870
+ if (issue) {
152871
+ throw new Error(issue);
152872
+ }
152873
+ validateGroups(pool, input.groups);
152874
+ const client2 = await getClient();
152875
+ try {
152876
+ await client2.send(new AdminCreateUserCommand({
152877
+ UserPoolId: pool.userPoolId,
152878
+ Username: input.username,
152879
+ TemporaryPassword: input.password
152880
+ }));
152881
+ } catch (error3) {
152882
+ if (error3 instanceof UsernameExistsException) {
152883
+ throw new Error("The user already exists");
152884
+ }
152885
+ throw error3;
152886
+ }
152887
+ await client2.send(new AdminSetUserPasswordCommand({
152888
+ UserPoolId: pool.userPoolId,
152889
+ Username: input.username,
152890
+ Password: input.password,
152891
+ Permanent: true
152892
+ }));
152893
+ for (const group4 of input.groups) {
152894
+ await client2.send(new AdminAddUserToGroupCommand({
152895
+ UserPoolId: pool.userPoolId,
152896
+ Username: input.username,
152897
+ GroupName: group4
152898
+ }));
152899
+ }
152900
+ },
152901
+ async updateUser(id, input) {
152902
+ const pool = getPool(id);
152903
+ validateGroups(pool, input.groups);
152904
+ if (input.password) {
152905
+ const issue = validatePassword(pool, input.password);
152906
+ if (issue) {
152907
+ throw new Error(issue);
152908
+ }
152909
+ }
152910
+ const client2 = await getClient();
152911
+ let oldGroups;
152912
+ try {
152913
+ await client2.send(new AdminGetUserCommand({
152914
+ UserPoolId: pool.userPoolId,
152915
+ Username: input.username
152916
+ }));
152917
+ oldGroups = await listUserGroups(pool.userPoolId, input.username);
152918
+ } catch (error3) {
152919
+ if (error3 instanceof UserNotFoundException) {
152920
+ throw new Error("The user does not exist");
152921
+ }
152922
+ throw error3;
152923
+ }
152924
+ if (input.password) {
152925
+ await client2.send(new AdminSetUserPasswordCommand({
152926
+ UserPoolId: pool.userPoolId,
152927
+ Username: input.username,
152928
+ Password: input.password,
152929
+ Permanent: true
152930
+ }));
152931
+ }
152932
+ const removed = oldGroups.filter((group4) => !input.groups.includes(group4));
152933
+ const added = input.groups.filter((group4) => !oldGroups.includes(group4));
152934
+ for (const group4 of removed) {
152935
+ await client2.send(new AdminRemoveUserFromGroupCommand({
152936
+ UserPoolId: pool.userPoolId,
152937
+ Username: input.username,
152938
+ GroupName: group4
152939
+ }));
152940
+ }
152941
+ for (const group4 of added) {
152942
+ await client2.send(new AdminAddUserToGroupCommand({
152943
+ UserPoolId: pool.userPoolId,
152944
+ Username: input.username,
152945
+ GroupName: group4
152946
+ }));
152947
+ }
152948
+ }
152949
+ };
152950
+ };
152951
+
152673
152952
  // src/feature/auth/index.ts
152674
152953
  import { toDays as toDays4, toHours } from "@awsless/duration";
152675
152954
  var authFeature = defineFeature({
152676
152955
  name: "auth",
152956
+ onDev: authOnDev,
152677
152957
  async onTypeGen(ctx) {
152678
152958
  const gen = new TypeFile("awsless");
152679
152959
  const resources = new TypeObject(1);
@@ -154743,6 +155023,9 @@ var decodeAwsChunked = (body) => {
154743
155023
  }
154744
155024
  return Buffer.concat(chunks);
154745
155025
  };
155026
+ var stripAnsi2 = (line) => {
155027
+ return line.replaceAll(/\x1b\[[0-9;?]*[a-zA-Z]/g, "");
155028
+ };
154746
155029
 
154747
155030
  // src/dev/servers/ssm.ts
154748
155031
  var createSsmServer = (props) => {
@@ -157981,7 +158264,20 @@ var startDevRouter = async (props) => {
157981
158264
  }
157982
158265
  const body = Buffer.from(await request.arrayBuffer());
157983
158266
  const sourceIp = server2.requestIP(request)?.address ?? "127.0.0.1";
157984
- const result = await props.dispatch(formatWebEvent(request, route, body, url, sourceIp));
158267
+ let result;
158268
+ try {
158269
+ result = await props.dispatch(formatWebEvent(request, route, body, url, sourceIp));
158270
+ } catch (error3) {
158271
+ props.onError?.(error3, route.routeKey);
158272
+ const detail = error3 instanceof Error ? error3.stack ?? error3.message : String(error3);
158273
+ return new Response(`500: Internal Error
158274
+
158275
+ ${route.routeKey}
158276
+ ${detail}`, {
158277
+ status: 500,
158278
+ headers: { "content-type": "text/plain" }
158279
+ });
158280
+ }
157985
158281
  return toResponse(result);
157986
158282
  },
157987
158283
  websocket: {
@@ -158766,7 +159062,7 @@ var planStaticRoutes = (files, sitePath) => {
158766
159062
  };
158767
159063
 
158768
159064
  // src/feature/site/dev.ts
158769
- var stripAnsi2 = (line) => {
159065
+ var stripAnsi3 = (line) => {
158770
159066
  return line.replaceAll(/\x1b\[[0-9;?]*[a-zA-Z]/g, "");
158771
159067
  };
158772
159068
  var binPath = (from) => {
@@ -158819,7 +159115,7 @@ var siteOnDev = async (ctx) => {
158819
159115
  const capture = (chunk3) => {
158820
159116
  for (const raw of chunk3.toString().split(`
158821
159117
  `)) {
158822
- const line = stripAnsi2(raw);
159118
+ const line = stripAnsi3(raw);
158823
159119
  if (line.trim() === "") {
158824
159120
  continue;
158825
159121
  }
@@ -162623,7 +162919,7 @@ var routerFeature = defineFeature({
162623
162919
  for (const [id, patterns] of Object.entries(stackConfig.routes ?? {})) {
162624
162920
  for (const pattern of Object.keys(patterns)) {
162625
162921
  const slug = kebabCase(pattern).slice(0, 20);
162626
- const routeKey = formatRouteKey(stackConfig.name, "route", `${slug || "root"}-${shortId(`${id}:${pattern}`)}`);
162922
+ const routeKey = formatRouteKey(stackConfig.name, "route", `${slug || "root"}-${shortId(pattern)}`);
162627
162923
  ctx.addRoute({
162628
162924
  routerId: id,
162629
162925
  pattern,
@@ -164582,11 +164878,11 @@ var deploy = (program3) => {
164582
164878
 
164583
164879
  // src/cli/command/auth/user/create.ts
164584
164880
  import {
164585
- AdminAddUserToGroupCommand,
164586
- AdminCreateUserCommand,
164587
- AdminSetUserPasswordCommand,
164588
- CognitoIdentityProviderClient,
164589
- UsernameExistsException
164881
+ AdminAddUserToGroupCommand as AdminAddUserToGroupCommand2,
164882
+ AdminCreateUserCommand as AdminCreateUserCommand2,
164883
+ AdminSetUserPasswordCommand as AdminSetUserPasswordCommand2,
164884
+ CognitoIdentityProviderClient as CognitoIdentityProviderClient2,
164885
+ UsernameExistsException as UsernameExistsException2
164590
164886
  } from "@aws-sdk/client-cognito-identity-provider";
164591
164887
  var create = (program3) => {
164592
164888
  program3.command("create").description("Create an user in your userpool").option("--pool <name>", "The auth userpool name").option("--username <username>", "The username for the new user").option("--password <password>", "The password for the new user").option("--groups <groups...>", "The groups to add the new user to").action(async (options) => {
@@ -164724,7 +165020,7 @@ var create = (program3) => {
164724
165020
  }))
164725
165021
  });
164726
165022
  }
164727
- const client = new CognitoIdentityProviderClient({
165023
+ const client = new CognitoIdentityProviderClient2({
164728
165024
  region,
164729
165025
  credentials: credentials2
164730
165026
  });
@@ -164734,18 +165030,18 @@ var create = (program3) => {
164734
165030
  errorMessage: "Failed creating user.",
164735
165031
  async task() {
164736
165032
  try {
164737
- await client.send(new AdminCreateUserCommand({
165033
+ await client.send(new AdminCreateUserCommand2({
164738
165034
  UserPoolId: userPoolId,
164739
165035
  Username: username,
164740
165036
  TemporaryPassword: password2
164741
165037
  }));
164742
165038
  } catch (error3) {
164743
- if (error3 instanceof UsernameExistsException) {
165039
+ if (error3 instanceof UsernameExistsException2) {
164744
165040
  throw new ExpectedError("User already exists");
164745
165041
  }
164746
165042
  throw error3;
164747
165043
  }
164748
- await client.send(new AdminSetUserPasswordCommand({
165044
+ await client.send(new AdminSetUserPasswordCommand2({
164749
165045
  UserPoolId: userPoolId,
164750
165046
  Username: username,
164751
165047
  Password: password2,
@@ -164753,7 +165049,7 @@ var create = (program3) => {
164753
165049
  }));
164754
165050
  if (groups.length > 0) {
164755
165051
  for (const group4 of groups) {
164756
- await client.send(new AdminAddUserToGroupCommand({
165052
+ await client.send(new AdminAddUserToGroupCommand2({
164757
165053
  UserPoolId: userPoolId,
164758
165054
  Username: username,
164759
165055
  GroupName: group4
@@ -164768,13 +165064,13 @@ var create = (program3) => {
164768
165064
 
164769
165065
  // src/cli/command/auth/user/update.ts
164770
165066
  import {
164771
- AdminAddUserToGroupCommand as AdminAddUserToGroupCommand2,
164772
- AdminGetUserCommand,
164773
- AdminListGroupsForUserCommand,
164774
- AdminRemoveUserFromGroupCommand,
164775
- AdminSetUserPasswordCommand as AdminSetUserPasswordCommand2,
164776
- CognitoIdentityProviderClient as CognitoIdentityProviderClient2,
164777
- UserNotFoundException
165067
+ AdminAddUserToGroupCommand as AdminAddUserToGroupCommand3,
165068
+ AdminGetUserCommand as AdminGetUserCommand2,
165069
+ AdminListGroupsForUserCommand as AdminListGroupsForUserCommand2,
165070
+ AdminRemoveUserFromGroupCommand as AdminRemoveUserFromGroupCommand2,
165071
+ AdminSetUserPasswordCommand as AdminSetUserPasswordCommand3,
165072
+ CognitoIdentityProviderClient as CognitoIdentityProviderClient3,
165073
+ UserNotFoundException as UserNotFoundException2
164778
165074
  } from "@aws-sdk/client-cognito-identity-provider";
164779
165075
  var update = (program3) => {
164780
165076
  program3.command("update").description("Update an user in your userpool").option("--pool <name>", "The auth userpool name").option("--username <username>", "The username of the user").option("--password <password>", "The new password for the user").option("--groups <groups...>", "The groups the user should be in, replacing the current groups").action(async (options) => {
@@ -164861,7 +165157,7 @@ var update = (program3) => {
164861
165157
  }
164862
165158
  });
164863
165159
  }
164864
- const client = new CognitoIdentityProviderClient2({
165160
+ const client = new CognitoIdentityProviderClient3({
164865
165161
  region,
164866
165162
  credentials: credentials2
164867
165163
  });
@@ -164871,12 +165167,12 @@ var update = (program3) => {
164871
165167
  errorMessage: `Failed fetching user info.`,
164872
165168
  async task() {
164873
165169
  try {
164874
- await client.send(new AdminGetUserCommand({
165170
+ await client.send(new AdminGetUserCommand2({
164875
165171
  UserPoolId: userPoolId,
164876
165172
  Username: username
164877
165173
  }));
164878
165174
  } catch (error3) {
164879
- if (error3 instanceof UserNotFoundException) {
165175
+ if (error3 instanceof UserNotFoundException2) {
164880
165176
  throw new ExpectedError("User does not exist");
164881
165177
  }
164882
165178
  throw error3;
@@ -164884,7 +165180,7 @@ var update = (program3) => {
164884
165180
  const groups = [];
164885
165181
  let token;
164886
165182
  do {
164887
- const result = await client.send(new AdminListGroupsForUserCommand({
165183
+ const result = await client.send(new AdminListGroupsForUserCommand2({
164888
165184
  UserPoolId: userPoolId,
164889
165185
  Username: username,
164890
165186
  NextToken: token
@@ -164958,7 +165254,7 @@ var update = (program3) => {
164958
165254
  errorMessage: "Failed updating user.",
164959
165255
  async task() {
164960
165256
  if (password2) {
164961
- await client.send(new AdminSetUserPasswordCommand2({
165257
+ await client.send(new AdminSetUserPasswordCommand3({
164962
165258
  UserPoolId: userPoolId,
164963
165259
  Username: username,
164964
165260
  Password: password2,
@@ -164970,14 +165266,14 @@ var update = (program3) => {
164970
165266
  const removedGroups = oldGroupSet.difference(newGroupSet);
164971
165267
  const addedGroups = newGroupSet.difference(oldGroupSet);
164972
165268
  for (const group4 of removedGroups) {
164973
- await client.send(new AdminRemoveUserFromGroupCommand({
165269
+ await client.send(new AdminRemoveUserFromGroupCommand2({
164974
165270
  UserPoolId: userPoolId,
164975
165271
  Username: username,
164976
165272
  GroupName: group4
164977
165273
  }));
164978
165274
  }
164979
165275
  for (const group4 of addedGroups) {
164980
- await client.send(new AdminAddUserToGroupCommand2({
165276
+ await client.send(new AdminAddUserToGroupCommand3({
164981
165277
  UserPoolId: userPoolId,
164982
165278
  Username: username,
164983
165279
  GroupName: group4
@@ -164992,8 +165288,8 @@ var update = (program3) => {
164992
165288
  // src/cli/command/auth/user/delete.ts
164993
165289
  import {
164994
165290
  AdminDeleteUserCommand,
164995
- CognitoIdentityProviderClient as CognitoIdentityProviderClient3,
164996
- UserNotFoundException as UserNotFoundException2
165291
+ CognitoIdentityProviderClient as CognitoIdentityProviderClient4,
165292
+ UserNotFoundException as UserNotFoundException3
164997
165293
  } from "@aws-sdk/client-cognito-identity-provider";
164998
165294
  var del10 = (program3) => {
164999
165295
  program3.command("delete").description("Delete an user from your userpool").option("--pool <name>", "The auth userpool name").option("--username <username>", "The username of the user to delete").action(async (options) => {
@@ -165069,7 +165365,7 @@ var del10 = (program3) => {
165069
165365
  throw new Cancelled;
165070
165366
  }
165071
165367
  }
165072
- const client = new CognitoIdentityProviderClient3({
165368
+ const client = new CognitoIdentityProviderClient4({
165073
165369
  region,
165074
165370
  credentials: credentials2
165075
165371
  });
@@ -165084,7 +165380,7 @@ var del10 = (program3) => {
165084
165380
  Username: username
165085
165381
  }));
165086
165382
  } catch (error3) {
165087
- if (error3 instanceof UserNotFoundException2) {
165383
+ if (error3 instanceof UserNotFoundException3) {
165088
165384
  throw new ExpectedError(`User doesn't exist`);
165089
165385
  }
165090
165386
  throw error3;
@@ -166419,8 +166715,18 @@ var createBundleWorker = (props) => {
166419
166715
  AWSLESS_DEV_WORKER_PORT: String(port)
166420
166716
  }
166421
166717
  });
166422
- child.stdout?.on("data", (chunk3) => process.stdout.write(chunk3));
166423
- child.stderr?.on("data", (chunk3) => process.stderr.write(chunk3));
166718
+ const capture = (stream2) => (chunk3) => {
166719
+ process[stream2].write(chunk3);
166720
+ for (const raw of chunk3.toString().split(`
166721
+ `)) {
166722
+ const line = stripAnsi2(raw);
166723
+ if (line.trim() !== "") {
166724
+ props.onOutput?.(line, stream2);
166725
+ }
166726
+ }
166727
+ };
166728
+ child.stdout?.on("data", capture("stdout"));
166729
+ child.stderr?.on("data", capture("stderr"));
166424
166730
  child.on("exit", (code) => {
166425
166731
  if (code !== null && code !== 0) {
166426
166732
  debug(`Bundle worker exited with code ${code}`);
@@ -166527,6 +166833,7 @@ var dashboardHtml = `<!doctype html>
166527
166833
  .logs .line { display: flex; gap: 8px; padding: 1px 0; }
166528
166834
  .logs .time { color: var(--muted); flex-shrink: 0; }
166529
166835
  .logs .text { white-space: pre-wrap; word-break: break-word; }
166836
+ .logs .line.error .text { color: var(--bad); }
166530
166837
  .config-form { display: flex; flex-direction: column; gap: 8px; max-width: 520px; }
166531
166838
  .config-form .field { display: grid; grid-template-columns: 180px 1fr; gap: 12px; align-items: center; }
166532
166839
  .config-form .name { color: var(--muted); overflow-wrap: anywhere; }
@@ -166539,6 +166846,8 @@ var dashboardHtml = `<!doctype html>
166539
166846
  font: inherit;
166540
166847
  }
166541
166848
  .config-form input::placeholder { color: var(--muted); }
166849
+ .groups { display: flex; flex-wrap: wrap; gap: 4px 16px; }
166850
+ .groups .group { display: flex; align-items: center; gap: 4px; cursor: pointer; }
166542
166851
  nav {
166543
166852
  border-right: 1px solid var(--border);
166544
166853
  overflow-y: auto;
@@ -166756,7 +167065,9 @@ const GROUPS = [
166756
167065
  ['search', 'Searches'],
166757
167066
  ['store', 'Stores'],
166758
167067
  ['config', 'Config'],
167068
+ ['auth', 'Auth'],
166759
167069
  ['email', 'Emails'],
167070
+ ['worker', 'Worker'],
166760
167071
  ['route', 'Routes'],
166761
167072
  ]
166762
167073
 
@@ -167042,7 +167353,7 @@ const attachLogFeed = (main, channel) => {
167042
167353
  const data = JSON.parse(message.data)
167043
167354
 
167044
167355
  feed.querySelector('.empty')?.remove()
167045
- feed.append($('div', { className: 'line' }, [
167356
+ feed.append($('div', { className: 'line' + (data.error ? ' error' : '') }, [
167046
167357
  $('span', { className: 'time' }, new Date(data.date).toLocaleTimeString()),
167047
167358
  $('span', { className: 'text' }, data.line),
167048
167359
  ]))
@@ -167372,6 +167683,138 @@ const configPanel = async (main) => {
167372
167683
  main.append(form, $('div', { className: 'actions' }, [save, status]))
167373
167684
  }
167374
167685
 
167686
+ // The users of a real deployed auth pool, with the same create &
167687
+ // group-update operations as the auth user cli commands.
167688
+ const authPanel = async (main, r) => {
167689
+ const holder = $('div', {}, $('p', { className: 'empty' }, 'Loading users...'))
167690
+ main.append(holder)
167691
+
167692
+ const groupBoxes = (groups, selected) => {
167693
+ const boxes = new Map()
167694
+ const row = $('div', { className: 'groups' })
167695
+
167696
+ for (const group of groups) {
167697
+ const box = $('input', { type: 'checkbox', checked: selected.includes(group) })
167698
+ boxes.set(group, box)
167699
+ row.append($('label', { className: 'group' }, [box, ' ' + group]))
167700
+ }
167701
+
167702
+ return { row, selected: () => [...boxes].filter(([, box]) => box.checked).map(([group]) => group) }
167703
+ }
167704
+
167705
+ try {
167706
+ const data = await api('/api/auth?pool=' + encodeURIComponent(r.id))
167707
+ holder.innerHTML = ''
167708
+
167709
+ // --------------------------------------------------------------
167710
+ // The user list, each row expanding into its group/password form.
167711
+
167712
+ if (data.users.length === 0) {
167713
+ holder.append($('p', { className: 'empty' }, 'The pool has no users.'))
167714
+ } else {
167715
+ const editRow = $('tr', { style: 'display: none' })
167716
+ const table = $('table', {}, [
167717
+ $('tr', {}, ['username', 'email', 'status', 'groups', 'created'].map(c => $('th', {}, c))),
167718
+ ])
167719
+
167720
+ for (const user of data.users) {
167721
+ const row = $('tr', {}, [
167722
+ $('td', {}, user.username),
167723
+ $('td', {}, user.email ?? ''),
167724
+ $('td', {}, user.enabled ? (user.status ?? '') : 'DISABLED'),
167725
+ $('td', {}, user.groups.join(', ')),
167726
+ $('td', {}, user.createdAt ? new Date(user.createdAt).toLocaleString() : ''),
167727
+ ])
167728
+
167729
+ row.style.cursor = 'pointer'
167730
+ row.onclick = () => {
167731
+ const groups = groupBoxes(data.groups, user.groups)
167732
+ const password = $('input', { type: 'password', placeholder: 'unchanged', spellcheck: false })
167733
+ const status = $('span', { className: 'status' })
167734
+ const save = $('button', { className: 'primary', textContent: 'Save' })
167735
+
167736
+ save.onclick = async () => {
167737
+ save.disabled = true
167738
+ try {
167739
+ await api('/api/auth/update', {
167740
+ method: 'POST',
167741
+ body: JSON.stringify({
167742
+ pool: r.id,
167743
+ username: user.username,
167744
+ password: password.value,
167745
+ groups: groups.selected(),
167746
+ }),
167747
+ })
167748
+ main.innerHTML = ''
167749
+ renderResource(main)
167750
+ return
167751
+ } catch (error) {
167752
+ status.textContent = String(error.message ?? error)
167753
+ }
167754
+ save.disabled = false
167755
+ }
167756
+
167757
+ editRow.innerHTML = ''
167758
+ editRow.style.display = ''
167759
+ editRow.append($('td', { colSpan: 5 }, $('div', { className: 'config-form' }, [
167760
+ $('label', { className: 'field' }, [$('span', { className: 'name' }, 'groups'), groups.row]),
167761
+ $('label', { className: 'field' }, [$('span', { className: 'name' }, 'new password'), password]),
167762
+ $('div', { className: 'actions' }, [save, status]),
167763
+ ])))
167764
+ row.after(editRow)
167765
+ }
167766
+
167767
+ table.append(row)
167768
+ }
167769
+
167770
+ holder.append(table)
167771
+ }
167772
+
167773
+ // --------------------------------------------------------------
167774
+ // Create a new user.
167775
+
167776
+ const username = $('input', { placeholder: 'username', spellcheck: false })
167777
+ const password = $('input', { type: 'password', placeholder: 'password', spellcheck: false })
167778
+ const groups = groupBoxes(data.groups, [])
167779
+ const status = $('span', { className: 'status' })
167780
+ const create = $('button', { className: 'primary', textContent: 'Create user' })
167781
+
167782
+ create.onclick = async () => {
167783
+ create.disabled = true
167784
+ try {
167785
+ await api('/api/auth/create', {
167786
+ method: 'POST',
167787
+ body: JSON.stringify({
167788
+ pool: r.id,
167789
+ username: username.value,
167790
+ password: password.value,
167791
+ groups: groups.selected(),
167792
+ }),
167793
+ })
167794
+ main.innerHTML = ''
167795
+ renderResource(main)
167796
+ return
167797
+ } catch (error) {
167798
+ status.textContent = String(error.message ?? error)
167799
+ }
167800
+ create.disabled = false
167801
+ }
167802
+
167803
+ holder.append(
167804
+ $('h3', {}, 'Create user'),
167805
+ $('div', { className: 'config-form' }, [
167806
+ $('label', { className: 'field' }, [$('span', { className: 'name' }, 'username'), username]),
167807
+ $('label', { className: 'field' }, [$('span', { className: 'name' }, 'password'), password]),
167808
+ $('label', { className: 'field' }, [$('span', { className: 'name' }, 'groups'), groups.row]),
167809
+ $('div', { className: 'actions' }, [create, status]),
167810
+ ]),
167811
+ )
167812
+ } catch (error) {
167813
+ holder.innerHTML = ''
167814
+ holder.append($('pre', { className: 'result error' }, String(error.message ?? error)))
167815
+ }
167816
+ }
167817
+
167375
167818
  const renderResource = main => {
167376
167819
  const r = view.resource
167377
167820
  const back = $('button', { className: 'back' }, '\u2190 ' + groupTitle(r.kind))
@@ -167395,6 +167838,7 @@ const renderResource = main => {
167395
167838
  if (r.kind === 'cache') return cachePanel(main, r)
167396
167839
  if (r.kind === 'store') return storePanel(main, r)
167397
167840
  if (r.kind === 'config') return configPanel(main)
167841
+ if (r.kind === 'auth') return authPanel(main, r)
167398
167842
  if (r.kind === 'route' || r.kind === 'site') {
167399
167843
  const url = r.url ?? r.detail
167400
167844
  main.append($('p', {}, $('a', { href: url, target: '_blank', style: 'color: var(--accent)' }, url)))
@@ -167776,6 +168220,36 @@ var createDashboardServer = (props) => {
167776
168220
  if (url.pathname === "/api/emails") {
167777
168221
  return { status: 200, body: JSON.stringify({ emails: props.getEmails?.() ?? [] }) };
167778
168222
  }
168223
+ if (url.pathname.startsWith("/api/auth") && props.auth) {
168224
+ const auth2 = props.auth;
168225
+ try {
168226
+ if (url.pathname === "/api/auth" && req.method === "GET") {
168227
+ const pool = url.searchParams.get("pool") ?? "";
168228
+ return {
168229
+ status: 200,
168230
+ body: JSON.stringify({
168231
+ ...auth2.describePool(pool),
168232
+ users: await auth2.listUsers(pool)
168233
+ })
168234
+ };
168235
+ }
168236
+ if (url.pathname === "/api/auth/create" && req.method === "POST") {
168237
+ const { pool, username, password: password2, groups } = JSON.parse((await readBody3(req)).toString() || "{}");
168238
+ await auth2.createUser(pool, { username, password: password2, groups: groups ?? [] });
168239
+ return { status: 200, body: JSON.stringify({ ok: true }) };
168240
+ }
168241
+ if (url.pathname === "/api/auth/update" && req.method === "POST") {
168242
+ const { pool, username, password: password2, groups } = JSON.parse((await readBody3(req)).toString() || "{}");
168243
+ await auth2.updateUser(pool, { username, password: password2 || undefined, groups: groups ?? [] });
168244
+ return { status: 200, body: JSON.stringify({ ok: true }) };
168245
+ }
168246
+ } catch (error3) {
168247
+ return {
168248
+ status: 400,
168249
+ body: JSON.stringify({ error: error3 instanceof Error ? error3.message : String(error3) })
168250
+ };
168251
+ }
168252
+ }
167779
168253
  if (url.pathname === "/api/config") {
167780
168254
  if (req.method === "PUT") {
167781
168255
  const values2 = JSON.parse((await readBody3(req)).toString() || "{}");
@@ -168160,7 +168634,21 @@ var startDev = async (props) => {
168160
168634
  workspace = await loadWorkspace3(directories.root);
168161
168635
  await buildAll();
168162
168636
  });
168163
- const worker = createBundleWorker({ buildDir, env: env4, functionName: bundleName });
168637
+ const emitWorkerLine = (line, error3 = false) => {
168638
+ dev.events.emit("worker", { date: Date.now(), line, error: error3 });
168639
+ };
168640
+ const worker = createBundleWorker({
168641
+ buildDir,
168642
+ env: env4,
168643
+ functionName: bundleName,
168644
+ onOutput: (line, stream2) => emitWorkerLine(line, stream2 === "stderr")
168645
+ });
168646
+ dev.resources.push({
168647
+ kind: "worker",
168648
+ id: "bundle",
168649
+ channel: "worker",
168650
+ detail: "The output & errors of the local bundle worker"
168651
+ });
168164
168652
  let dirty = false;
168165
168653
  let fresh;
168166
168654
  let restartNeeded = false;
@@ -168236,7 +168724,13 @@ var startDev = async (props) => {
168236
168724
  routers.push(await startDevRouter({
168237
168725
  routes: dev.routes.filter((route) => route.routerId === id),
168238
168726
  port,
168239
- dispatch
168727
+ dispatch,
168728
+ onError(error3, routeKey) {
168729
+ const detail = error3 instanceof Error ? error3.stack ?? error3.message : String(error3);
168730
+ process.stderr.write(`Route ${routeKey} failed: ${detail}
168731
+ `);
168732
+ emitWorkerLine(`Route ${routeKey} failed: ${detail}`, true);
168733
+ }
168240
168734
  }));
168241
168735
  }
168242
168736
  const dashboardPort = props.port;
@@ -168255,6 +168749,10 @@ var startDev = async (props) => {
168255
168749
  configFile: join54(directories.output, "local", "config.json"),
168256
168750
  getEmails: () => props.pool.peek("shim:ses-email")?.server.list() ?? [],
168257
168751
  configPulled: Object.keys(props.pool.peek("config:pull") ?? {}),
168752
+ auth: createAuthAdmin({
168753
+ appConfig,
168754
+ resolvedPools: () => props.pool.peek("auth:pull")
168755
+ }),
168258
168756
  events: dev.events
168259
168757
  });
168260
168758
  dashboard.connect(dispatch);
@@ -452,7 +452,9 @@ var createBundle = (handlers) => {
452
452
  }
453
453
  throw new Error("Unknown bundle route: " + match2.key);
454
454
  }
455
- console.trace(`Bundle route: ${match2.key}`);
455
+ if (process.env.AWSLESS_ENV !== "local") {
456
+ console.trace(`Bundle route: ${match2.key}`);
457
+ }
456
458
  process.env.AWSLESS_ROUTE = match2.key;
457
459
  return withBundleRouteContext(match2.key, internalInvoke, async () => {
458
460
  const handle = await load();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awsless/cli",
3
- "version": "0.0.46-local.44",
3
+ "version": "0.0.46-local.46",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -38,19 +38,19 @@
38
38
  "@opensearch-project/opensearch": "^2.13.0",
39
39
  "rolldown": "1.2.1",
40
40
  "vitest": "4.1.10",
41
- "@awsless/ts-file-cache": "^0.0.16",
42
- "@awsless/dynamodb-server": "^0.1.8"
41
+ "@awsless/dynamodb-server": "^0.1.8",
42
+ "@awsless/ts-file-cache": "^0.0.16"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@awsless/big-float": "^0.1.7",
46
- "@awsless/duration": "^0.0.4",
47
- "@awsless/lambda": "^0.0.47",
48
46
  "@awsless/dynamodb": "^0.3.22",
47
+ "@awsless/duration": "^0.0.4",
49
48
  "@awsless/s3": "^0.0.22",
50
- "@awsless/json": "^0.0.11",
49
+ "@awsless/lambda": "^0.0.47",
51
50
  "@awsless/weak-cache": "^0.0.1",
52
- "awsless": "^0.0.15-local.11",
53
- "@awsless/validate": "^0.1.7"
51
+ "@awsless/json": "^0.0.11",
52
+ "@awsless/validate": "^0.1.7",
53
+ "awsless": "^0.0.15-local.11"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@aws-sdk/client-cloudformation": "^3.369.0",
@@ -120,25 +120,25 @@
120
120
  "zip-a-folder": "^3.1.6",
121
121
  "zod": "^3.24.2",
122
122
  "zod-to-json-schema": "^3.24.3",
123
- "@awsless/cloudwatch": "^0.0.1",
124
123
  "@awsless/clui": "^0.0.9",
125
124
  "@awsless/big-float": "^0.1.7",
126
- "@awsless/iot": "^0.0.5",
127
125
  "@awsless/duration": "^0.0.4",
126
+ "@awsless/lambda": "^0.0.47",
128
127
  "@awsless/dynamodb": "^0.3.22",
129
- "@awsless/json": "^0.0.11",
130
128
  "@awsless/open-search": "^0.0.26",
129
+ "@awsless/iot": "^0.0.5",
130
+ "@awsless/cloudwatch": "^0.0.1",
131
+ "@awsless/json": "^0.0.11",
131
132
  "@awsless/redis": "^0.1.13",
132
133
  "@awsless/s3": "^0.0.22",
134
+ "@awsless/sqs": "^0.0.24",
133
135
  "@awsless/size": "^0.0.2",
136
+ "@awsless/scheduler": "^0.0.5",
134
137
  "@awsless/sns": "^0.0.11",
135
- "@awsless/ssm": "^0.0.8",
136
- "@awsless/lambda": "^0.0.47",
137
138
  "@awsless/validate": "^0.1.7",
139
+ "awsless": "^0.0.15-local.11",
138
140
  "@awsless/weak-cache": "^0.0.1",
139
- "@awsless/sqs": "^0.0.24",
140
- "@awsless/scheduler": "^0.0.5",
141
- "awsless": "^0.0.15-local.11"
141
+ "@awsless/ssm": "^0.0.8"
142
142
  },
143
143
  "scripts": {
144
144
  "test": "bun cli/build-handlers.ts && pnpm vitest",