@awsless/awsless 0.0.112 → 0.0.113

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
@@ -1423,18 +1423,18 @@ var TypeObject = class {
1423
1423
  this.readonly = readonly;
1424
1424
  }
1425
1425
  types = /* @__PURE__ */ new Map();
1426
- addType(name, type) {
1426
+ add(name, type) {
1427
1427
  const value = type.toString();
1428
1428
  if (value) {
1429
- this.types.set(camelCase(name), value);
1429
+ this.types.set(name, value);
1430
1430
  }
1431
1431
  return this;
1432
1432
  }
1433
+ addType(name, type) {
1434
+ return this.add(camelCase(name), type);
1435
+ }
1433
1436
  addConst(name, type) {
1434
- if (type) {
1435
- this.types.set(constantCase3(name), type);
1436
- }
1437
- return this;
1437
+ return this.add(constantCase3(name), type);
1438
1438
  }
1439
1439
  toString() {
1440
1440
  if (!this.types.size) {
@@ -4417,8 +4417,10 @@ var ElbEventSource = class extends Group {
4417
4417
  };
4418
4418
 
4419
4419
  // src/plugins/http.ts
4420
+ import { relative as relative4 } from "path";
4421
+ import { camelCase as camelCase4 } from "change-case";
4420
4422
  var RouteSchema = z18.custom((route) => {
4421
- return z18.string().regex(/^(POST|GET|PUT|DELETE|HEAD|OPTIONS)(\s\/[a-z0-9\+\_\-\/]*)$/ig).safeParse(route).success;
4423
+ return z18.string().regex(/^(POST|GET|PUT|DELETE|HEAD|OPTIONS)(\s\/[a-z0-9\+\_\-\/\{\}]*)$/gi).safeParse(route).success;
4422
4424
  }, "Invalid route");
4423
4425
  var parseRoute = (route) => {
4424
4426
  const [method, ...paths] = route.split(" ");
@@ -4471,12 +4473,51 @@ var httpPlugin = definePlugin({
4471
4473
  * }
4472
4474
  * }
4473
4475
  */
4474
- http: z18.record(
4475
- ResourceIdSchema,
4476
- z18.record(RouteSchema, FunctionSchema)
4477
- ).optional()
4476
+ http: z18.record(ResourceIdSchema, z18.record(RouteSchema, FunctionSchema)).optional()
4478
4477
  }).array()
4479
4478
  }),
4479
+ onTypeGen({ config: config2 }) {
4480
+ const types2 = new TypeGen("@awsless/awsless");
4481
+ const resources = new TypeObject(1);
4482
+ const api = {};
4483
+ for (const stack of config2.stacks) {
4484
+ for (const [id, routes] of Object.entries(stack.http || {})) {
4485
+ if (!(id in api))
4486
+ api[id] = {};
4487
+ for (const [route, props] of Object.entries(routes)) {
4488
+ const { path, method } = parseRoute(route);
4489
+ const file = typeof props === "string" ? props : props.file;
4490
+ if (!(method in api[id]))
4491
+ api[id][method] = {};
4492
+ api[id][method][path] = file;
4493
+ }
4494
+ }
4495
+ }
4496
+ for (const [id, routes] of Object.entries(api)) {
4497
+ const idType = new TypeObject(2);
4498
+ for (const [method, paths] of Object.entries(routes)) {
4499
+ const methodType = new TypeObject(3);
4500
+ for (const [path, file] of Object.entries(paths)) {
4501
+ const paramType = new TypeObject(4);
4502
+ for (const param of path.matchAll(/{([a-z0-9]+)}/g)) {
4503
+ paramType.addType(param[0], "string | number");
4504
+ }
4505
+ const varName = camelCase4(`${id}-${path}-${method}`);
4506
+ const relFile = relative4(directories.types, file);
4507
+ types2.addImport(varName, relFile);
4508
+ methodType.add(`'${path}'`, `Route<typeof ${varName}, ${paramType.toString() || "never"}>`);
4509
+ }
4510
+ idType.addConst(method, methodType);
4511
+ }
4512
+ resources.addType(id, idType);
4513
+ }
4514
+ types2.addCode(`type Query<F> = Parameters<F>[0]['request']['query']`);
4515
+ types2.addCode(`type Body<F> = Parameters<F>[0]['request']['body']`);
4516
+ types2.addCode(`type Response<F> = Awaited<ReturnType<F>>`);
4517
+ types2.addCode(`type Route<F, P> = { param: P, query: Query<F>, body: Body<F>, response: Response<F> }`);
4518
+ types2.addInterface("Http", resources);
4519
+ return types2.toString();
4520
+ },
4480
4521
  onApp({ config: config2, bootstrap: bootstrap2 }) {
4481
4522
  if (Object.keys(config2.defaults?.http || {}).length === 0) {
4482
4523
  return;
@@ -4494,18 +4535,13 @@ var httpPlugin = definePlugin({
4494
4535
  name: `${config2.name}-${id}`,
4495
4536
  type: "application",
4496
4537
  securityGroups: [securityGroup.id],
4497
- subnets: [
4498
- bootstrap2.get("public-subnet-1"),
4499
- bootstrap2.get("public-subnet-2")
4500
- ]
4538
+ subnets: [bootstrap2.get("public-subnet-1"), bootstrap2.get("public-subnet-2")]
4501
4539
  }).dependsOn(securityGroup);
4502
4540
  const listener = new Listener(id, {
4503
4541
  loadBalancerArn: loadBalancer.arn,
4504
4542
  port: 443,
4505
4543
  protocol: "https",
4506
- certificates: [
4507
- bootstrap2.get(`certificate-${props.domain}-arn`)
4508
- ],
4544
+ certificates: [bootstrap2.get(`certificate-${props.domain}-arn`)],
4509
4545
  defaultActions: [
4510
4546
  ListenerAction.fixedResponse(404, {
4511
4547
  contentType: "application/json",
@@ -5356,7 +5392,7 @@ var LocalDirectorySchema = z24.string().refine(async (path) => {
5356
5392
  }, `Directory doesn't exist`);
5357
5393
 
5358
5394
  // src/formation/resource/cloud-front/origin-request-policy.ts
5359
- import { camelCase as camelCase4 } from "change-case";
5395
+ import { camelCase as camelCase5 } from "change-case";
5360
5396
  var OriginRequestPolicy = class extends Resource {
5361
5397
  constructor(logicalId, props = {}) {
5362
5398
  super("AWS::CloudFront::OriginRequestPolicy", logicalId);
@@ -5372,15 +5408,15 @@ var OriginRequestPolicy = class extends Resource {
5372
5408
  OriginRequestPolicyConfig: {
5373
5409
  Name: this.name,
5374
5410
  CookiesConfig: {
5375
- CookieBehavior: camelCase4(this.props.cookie?.behavior ?? "all"),
5411
+ CookieBehavior: camelCase5(this.props.cookie?.behavior ?? "all"),
5376
5412
  ...this.attr("Cookies", this.props.cookie?.values)
5377
5413
  },
5378
5414
  HeadersConfig: {
5379
- HeaderBehavior: camelCase4(this.props.header?.behavior ?? "allViewer"),
5415
+ HeaderBehavior: camelCase5(this.props.header?.behavior ?? "allViewer"),
5380
5416
  ...this.attr("Headers", this.props.header?.values)
5381
5417
  },
5382
5418
  QueryStringsConfig: {
5383
- QueryStringBehavior: camelCase4(this.props.query?.behavior ?? "all"),
5419
+ QueryStringBehavior: camelCase5(this.props.query?.behavior ?? "all"),
5384
5420
  ...this.attr("QueryStrings", this.props.query?.values)
5385
5421
  }
5386
5422
  }
@@ -8310,7 +8346,7 @@ import commonjs3 from "@rollup/plugin-commonjs";
8310
8346
  import nodeResolve3 from "@rollup/plugin-node-resolve";
8311
8347
  import { swc as swc4 } from "rollup-plugin-swc3";
8312
8348
  import { getSuites, getTests } from "@vitest/runner/utils";
8313
- import { basename as basename3, dirname as dirname6, extname as extname2, join as join11, relative as relative4 } from "path";
8349
+ import { basename as basename3, dirname as dirname6, extname as extname2, join as join11, relative as relative5 } from "path";
8314
8350
 
8315
8351
  // src/cli/ui/layout/text-box.ts
8316
8352
  import wrapAnsi3 from "wrap-ansi";
@@ -8397,7 +8433,7 @@ var singleTester = (stack, dir, filters) => {
8397
8433
  return "";
8398
8434
  }
8399
8435
  const abs = join11(process.cwd(), path);
8400
- const rel = relative4(dir, abs);
8436
+ const rel = relative5(dir, abs);
8401
8437
  const ext = extname2(rel);
8402
8438
  if (!ext) {
8403
8439
  return path;
@@ -8814,7 +8850,6 @@ var test = (program2) => {
8814
8850
  program2.command("test").argument("[stacks...]", "Optionally filter stacks to test").option("-f --filters <string...>", "Optionally filter test files").description("Test your app").action(async (stacks, options) => {
8815
8851
  await layout(async (config2, write) => {
8816
8852
  const { tests } = await toApp(config2, stacks);
8817
- debug(stacks, options);
8818
8853
  if (tests.size === 0) {
8819
8854
  write(dialog("warning", ["No tests found"]));
8820
8855
  return;
package/dist/index.d.ts CHANGED
@@ -11241,6 +11241,44 @@ interface SearchResources {
11241
11241
  }
11242
11242
  declare const Search: SearchResources;
11243
11243
 
11244
+ interface Http {
11245
+ }
11246
+ type Method = 'GET' | 'POST';
11247
+ type Path = string;
11248
+ type Params = Record<string, string | number>;
11249
+ type Query = Record<string, string>;
11250
+ type Body = unknown;
11251
+ type Route = {
11252
+ param?: Params;
11253
+ query?: Query;
11254
+ body?: Body;
11255
+ response: unknown;
11256
+ };
11257
+ type Routes = Record<Path, Route>;
11258
+ type Schema = Partial<Record<Method, Routes>>;
11259
+ type GetRoute<S extends Schema, M extends keyof S, P extends keyof S[M]> = S[M] extends Routes ? S[M][P] : never;
11260
+ type Props<R extends Route> = {
11261
+ headers?: Record<string, string>;
11262
+ params?: R['param'] extends Params ? R['param'] : never;
11263
+ query?: R['query'] extends Query ? R['query'] : never;
11264
+ body?: R['body'] extends Body ? R['body'] : never;
11265
+ };
11266
+ type HttpClientHandle = (props: {
11267
+ method: Method;
11268
+ path: Path;
11269
+ headers: Headers;
11270
+ query?: Query;
11271
+ body?: Body;
11272
+ }) => unknown;
11273
+ declare const simpleHttpHandler: (host: string) => HttpClientHandle;
11274
+ declare class HttpClient<S extends Schema> {
11275
+ private handle;
11276
+ constructor(handle: HttpClientHandle);
11277
+ fetch<M extends keyof S, P extends keyof S[M]>(method: M, routeKey: Extract<P, string>, props?: Props<GetRoute<S, M, P>>): Promise<GetRoute<S, M, P>["response"]>;
11278
+ get<P extends keyof S['GET']>(routeKey: Extract<P, string>, props?: Props<GetRoute<S, 'GET', P>>): Promise<GetRoute<S, "GET", P>["response"]>;
11279
+ post<P extends keyof S['POST']>(routeKey: Extract<P, string>, props?: Props<GetRoute<S, 'POST', P>>): Promise<GetRoute<S, "POST", P>["response"]>;
11280
+ }
11281
+
11244
11282
  type FunctionProps<H extends Handler<S>, S extends BaseSchema> = {
11245
11283
  handle: H;
11246
11284
  schema?: S;
@@ -12101,4 +12139,4 @@ declare const defineStackConfig: (config: StackConfig) => StackConfig$1 | (Stack
12101
12139
  });
12102
12140
  declare const defineAppConfig: (config: AppConfig | AppConfigFactory<AppConfig>) => CombinedDefaultPluginsConfigInput | AppConfigFactory<CombinedDefaultPluginsConfigInput>;
12103
12141
 
12104
- export { APP, AppConfig, Auth, AuthResources, Cache, CacheResources, Config, ConfigResources, CronProps, Fn, Function, FunctionMock, FunctionMockResponse, FunctionProps, FunctionResources, Plugin, Queue, QueueMock, QueueMockResponse, QueueProps, QueueResources, STACK, Search, SearchResources, StackConfig, Store, StoreResources, Table, TableResources, Topic, TopicMock, TopicMockResponse, TopicProps, TopicResources, cron, defineAppConfig, definePlugin, defineStackConfig, func, getAuthName, getAuthProps, getCacheProps, getConfigName, getFunctionName, getGlobalResourceName, getLocalResourceName, getQueueName, getSearchName, getStoreName, getTableName, getTopicName, mockFunction, mockQueue, mockTopic, queue, topic };
12142
+ export { APP, AppConfig, Auth, AuthResources, Cache, CacheResources, Config, ConfigResources, CronProps, Fn, Function, FunctionMock, FunctionMockResponse, FunctionProps, FunctionResources, Http, HttpClient, HttpClientHandle, Plugin, Queue, QueueMock, QueueMockResponse, QueueProps, QueueResources, STACK, Search, SearchResources, StackConfig, Store, StoreResources, Table, TableResources, Topic, TopicMock, TopicMockResponse, TopicProps, TopicResources, cron, defineAppConfig, definePlugin, defineStackConfig, func, getAuthName, getAuthProps, getCacheProps, getConfigName, getFunctionName, getGlobalResourceName, getLocalResourceName, getQueueName, getSearchName, getStoreName, getTableName, getTopicName, mockFunction, mockQueue, mockTopic, queue, simpleHttpHandler, topic };
package/dist/index.js CHANGED
@@ -250,6 +250,49 @@ var Search = /* @__PURE__ */ createProxy((stack) => {
250
250
  });
251
251
  });
252
252
 
253
+ // src/node/http.ts
254
+ var simpleHttpHandler = (host) => {
255
+ return async ({ method, path, headers, body, query }) => {
256
+ const url = new URL(host, path);
257
+ if (query) {
258
+ for (const [key, value] of Object.entries(query)) {
259
+ url.searchParams.set(key, value);
260
+ }
261
+ }
262
+ headers.set("content-type", "application/json");
263
+ const response = await fetch(url, {
264
+ method,
265
+ headers,
266
+ body: body ? JSON.stringify(body) : void 0
267
+ });
268
+ const result = await response.json();
269
+ return result;
270
+ };
271
+ };
272
+ var HttpClient = class {
273
+ constructor(handle) {
274
+ this.handle = handle;
275
+ }
276
+ fetch(method, routeKey, props) {
277
+ const path = routeKey.replaceAll(/{([a-z0-1-]+)}/, (key) => {
278
+ return props?.params?.[key.substring(1, key.length - 1)].toString() ?? "";
279
+ });
280
+ return this.handle({
281
+ headers: new Headers(props?.headers),
282
+ query: props?.query,
283
+ body: props?.body,
284
+ method,
285
+ path
286
+ });
287
+ }
288
+ get(routeKey, props) {
289
+ return this.fetch("GET", routeKey, props);
290
+ }
291
+ post(routeKey, props) {
292
+ return this.fetch("POST", routeKey, props);
293
+ }
294
+ };
295
+
253
296
  // src/node/handle/function.ts
254
297
  import { lambda } from "@awsless/lambda";
255
298
  var func = (props) => {
@@ -358,6 +401,7 @@ export {
358
401
  Config,
359
402
  Fn,
360
403
  Function,
404
+ HttpClient,
361
405
  Queue,
362
406
  STACK,
363
407
  Search,
@@ -385,5 +429,6 @@ export {
385
429
  mockQueue,
386
430
  mockTopic,
387
431
  queue,
432
+ simpleHttpHandler,
388
433
  topic
389
434
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awsless/awsless",
3
- "version": "0.0.112",
3
+ "version": "0.0.113",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -24,11 +24,11 @@
24
24
  }
25
25
  },
26
26
  "peerDependencies": {
27
- "@awsless/redis": "^0.0.8",
28
27
  "@awsless/lambda": "^0.0.14",
28
+ "@awsless/sns": "^0.0.7",
29
29
  "@awsless/sqs": "^0.0.7",
30
+ "@awsless/redis": "^0.0.8",
30
31
  "@awsless/validate": "^0.0.10",
31
- "@awsless/sns": "^0.0.7",
32
32
  "@awsless/weak-cache": "^0.0.1",
33
33
  "@awsless/ssm": "^0.0.7"
34
34
  },