@awsless/cli 0.1.5 → 0.1.7
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/app.json +1 -1
- package/dist/app.stage.json +1 -1
- package/dist/bin.js +99 -16
- package/dist/handlers/pubsub-publisher.js +21 -21
- package/package.json +14 -14
package/dist/bin.js
CHANGED
|
@@ -108402,6 +108402,7 @@ import { join, normalize, relative } from "path";
|
|
|
108402
108402
|
var root = process.cwd();
|
|
108403
108403
|
var directories = {
|
|
108404
108404
|
root,
|
|
108405
|
+
buildFolder: "build",
|
|
108405
108406
|
get output() {
|
|
108406
108407
|
return join(this.root, ".awsless");
|
|
108407
108408
|
},
|
|
@@ -108412,7 +108413,7 @@ var directories = {
|
|
|
108412
108413
|
return join(this.output, "state");
|
|
108413
108414
|
},
|
|
108414
108415
|
get build() {
|
|
108415
|
-
return join(this.output,
|
|
108416
|
+
return join(this.output, this.buildFolder);
|
|
108416
108417
|
},
|
|
108417
108418
|
get types() {
|
|
108418
108419
|
return join(this.output, "types");
|
|
@@ -108427,6 +108428,9 @@ var directories = {
|
|
|
108427
108428
|
var setRoot = (path = root) => {
|
|
108428
108429
|
directories.root = path;
|
|
108429
108430
|
};
|
|
108431
|
+
var useDevBuildDir = () => {
|
|
108432
|
+
directories.buildFolder = "build-dev";
|
|
108433
|
+
};
|
|
108430
108434
|
var findRootDir = async (path, configFiles, level = 5) => {
|
|
108431
108435
|
if (!level) {
|
|
108432
108436
|
throw new TypeError("No awsless project found");
|
|
@@ -143957,6 +143961,14 @@ var createOpenSearchProvider = ({ credentials: credentials2, region }) => {
|
|
|
143957
143961
|
async updateResource(props) {
|
|
143958
143962
|
return apply(props.proposedState);
|
|
143959
143963
|
},
|
|
143964
|
+
async planResourceChange(props) {
|
|
143965
|
+
const prior = props.priorState;
|
|
143966
|
+
const proposed = props.proposedState;
|
|
143967
|
+
return {
|
|
143968
|
+
state: props.proposedState,
|
|
143969
|
+
requiresReplacement: !!prior && (prior.endpoint !== proposed?.endpoint || prior.index !== proposed?.index)
|
|
143970
|
+
};
|
|
143971
|
+
},
|
|
143960
143972
|
async deleteResource(props) {
|
|
143961
143973
|
const state = inputSchema.parse(props.state);
|
|
143962
143974
|
await getClient(state.endpoint).indices.delete({ index: state.index }, { ignore: [404] });
|
|
@@ -151126,7 +151138,7 @@ var JobDefaultSchema = exports_external.object({
|
|
|
151126
151138
|
|
|
151127
151139
|
// src/feature/search/schema.ts
|
|
151128
151140
|
var VersionSchema = exports_external.union([
|
|
151129
|
-
exports_external.enum(["2.13", "2.11", "2.9", "2.7", "2.5", "2.3", "1.3"]),
|
|
151141
|
+
exports_external.enum(["3.7", "3.5", "3.3", "3.1", "2.19", "2.17", "2.15", "2.13", "2.11", "2.9", "2.7", "2.5", "2.3", "1.3"]),
|
|
151130
151142
|
exports_external.string()
|
|
151131
151143
|
]).describe("Specify the OpenSearch engine version.");
|
|
151132
151144
|
var TypeSchema = exports_external.union([
|
|
@@ -151168,7 +151180,7 @@ var StorageSizeSchema = SizeSchema.refine(sizeMin(gibibytes(10)), "Minimum stora
|
|
|
151168
151180
|
var SearchDefaultSchema = exports_external.object({
|
|
151169
151181
|
type: TypeSchema.default("t3.small"),
|
|
151170
151182
|
count: CountSchema.default(1),
|
|
151171
|
-
version: VersionSchema.default("
|
|
151183
|
+
version: VersionSchema.default("3.7"),
|
|
151172
151184
|
storage: StorageSizeSchema.default("10 GB")
|
|
151173
151185
|
}).strict().default({}).describe("Configure the shared OpenSearch domain that backs every search index in your app.");
|
|
151174
151186
|
var IndexNameSchema = exports_external.string().regex(/^[a-z0-9][a-z0-9\-_.]*$/, 'Index names must be lowercase & start with a letter or number, like "users" or "game-events".');
|
|
@@ -158858,7 +158870,8 @@ var searchFeature = defineFeature({
|
|
|
158858
158870
|
})
|
|
158859
158871
|
}, {
|
|
158860
158872
|
retainOnDelete: ctx.appConfig.removal === "retain",
|
|
158861
|
-
import: ctx.import ? name : undefined
|
|
158873
|
+
import: ctx.import ? name : undefined,
|
|
158874
|
+
replaceOnChanges: ["engineVersion", "domainName"]
|
|
158862
158875
|
});
|
|
158863
158876
|
ctx.addEnv("SEARCH_DOMAIN", openSearch.endpointV2);
|
|
158864
158877
|
ctx.addPermission({
|
|
@@ -158872,7 +158885,8 @@ var searchFeature = defineFeature({
|
|
|
158872
158885
|
mappings: JSON.stringify(resolveSearchMappings(indexProps) ?? {}),
|
|
158873
158886
|
settings: JSON.stringify(indexProps.settings ?? {})
|
|
158874
158887
|
}, {
|
|
158875
|
-
retainOnDelete: ctx.appConfig.removal === "retain"
|
|
158888
|
+
retainOnDelete: ctx.appConfig.removal === "retain",
|
|
158889
|
+
replaceOnChanges: ["endpoint", "index"]
|
|
158876
158890
|
});
|
|
158877
158891
|
}
|
|
158878
158892
|
}
|
|
@@ -164570,11 +164584,16 @@ var startTest = async (props) => {
|
|
|
164570
164584
|
}
|
|
164571
164585
|
for (const error3 of module.errors()) {
|
|
164572
164586
|
const stack = error3.stacks?.[0];
|
|
164587
|
+
const { code, syscall, address, port } = error3;
|
|
164573
164588
|
errors3.push({
|
|
164574
164589
|
type: error3.name,
|
|
164575
164590
|
message: error3.message,
|
|
164576
164591
|
location: stack ? { line: stack.line, column: stack.column } : undefined,
|
|
164577
|
-
stack: error3.stack
|
|
164592
|
+
stack: error3.stack,
|
|
164593
|
+
code,
|
|
164594
|
+
syscall,
|
|
164595
|
+
address,
|
|
164596
|
+
port
|
|
164578
164597
|
});
|
|
164579
164598
|
}
|
|
164580
164599
|
}
|
|
@@ -164670,6 +164689,11 @@ var logTestErrors = (event) => {
|
|
|
164670
164689
|
}
|
|
164671
164690
|
}
|
|
164672
164691
|
};
|
|
164692
|
+
var formatModuleError = (error3) => {
|
|
164693
|
+
const syscall = [error3.syscall, error3.address, error3.port && `port ${error3.port}`].filter(Boolean).join(" ");
|
|
164694
|
+
return [error3.message, syscall && `(${syscall})`, `
|
|
164695
|
+
`, error3.stack ?? "(no stack captured)"].filter(Boolean).join(" ");
|
|
164696
|
+
};
|
|
164673
164697
|
var runTest = async (stack, dir, filters, workspace, opts) => {
|
|
164674
164698
|
await mkdir8(directories.test, { recursive: true });
|
|
164675
164699
|
const file2 = join49(directories.test, `${stack}.json`);
|
|
@@ -164697,15 +164721,26 @@ var runTest = async (stack, dir, filters, workspace, opts) => {
|
|
|
164697
164721
|
initialMessage: `Run tests for the ${color2.info(stack)} stack`,
|
|
164698
164722
|
errorMessage: `Running tests for the ${color2.info(stack)} stack failed`,
|
|
164699
164723
|
async task(ctx) {
|
|
164700
|
-
const
|
|
164724
|
+
const transient = (error3) => ["ECONNREFUSED", "ECONNRESET", "ETIMEDOUT", "EPIPE"].includes(error3.code ?? "") || ["ECONNREFUSED", "ECONNRESET", "ETIMEDOUT", "EPIPE"].some((code) => error3.message.includes(code));
|
|
164725
|
+
let result2 = await startTest({
|
|
164701
164726
|
dir,
|
|
164702
164727
|
filters,
|
|
164703
164728
|
env: opts.env
|
|
164704
164729
|
});
|
|
164730
|
+
if (result2.errors.length > 0 && result2.errors.every(transient)) {
|
|
164731
|
+
for (const error3 of result2.errors) {
|
|
164732
|
+
debug(`Transient module error in ${stack} tests, retrying once: ${formatModuleError(error3)}`);
|
|
164733
|
+
}
|
|
164734
|
+
await new Promise((resolve5) => setTimeout(resolve5, 1000));
|
|
164735
|
+
result2 = await startTest({
|
|
164736
|
+
dir,
|
|
164737
|
+
filters,
|
|
164738
|
+
env: opts.env
|
|
164739
|
+
});
|
|
164740
|
+
}
|
|
164705
164741
|
if (result2.errors.length > 0) {
|
|
164706
164742
|
for (const error3 of result2.errors) {
|
|
164707
|
-
debug(`Module error in ${stack} tests: ${error3
|
|
164708
|
-
${error3.stack ?? "(no stack captured)"}`);
|
|
164743
|
+
debug(`Module error in ${stack} tests: ${formatModuleError(error3)}`);
|
|
164709
164744
|
}
|
|
164710
164745
|
throw result2.errors.map((error3) => new ExpectedError(error3.type && error3.type !== "Error" ? `${error3.type}: ${error3.message}` : error3.message));
|
|
164711
164746
|
}
|
|
@@ -167237,8 +167272,10 @@ var createBundleWorker = (props) => {
|
|
|
167237
167272
|
}
|
|
167238
167273
|
}
|
|
167239
167274
|
}
|
|
167240
|
-
|
|
167275
|
+
if (!props.quiet?.()) {
|
|
167276
|
+
process[stream2].write((route ? `[${route}] ` : "") + text2 + `
|
|
167241
167277
|
`);
|
|
167278
|
+
}
|
|
167242
167279
|
const clean = stripAnsi2(text2);
|
|
167243
167280
|
if (clean.trim() !== "") {
|
|
167244
167281
|
props.onOutput?.(clean, stream2, route);
|
|
@@ -167415,6 +167452,13 @@ var dashboardHtml = `<!doctype html>
|
|
|
167415
167452
|
cursor: pointer;
|
|
167416
167453
|
}
|
|
167417
167454
|
nav h1 span { color: var(--muted); font-weight: normal; }
|
|
167455
|
+
nav h3 {
|
|
167456
|
+
font-size: 10px;
|
|
167457
|
+
text-transform: uppercase;
|
|
167458
|
+
letter-spacing: 1px;
|
|
167459
|
+
color: var(--muted);
|
|
167460
|
+
margin: 14px 8px 4px;
|
|
167461
|
+
}
|
|
167418
167462
|
nav button {
|
|
167419
167463
|
display: flex;
|
|
167420
167464
|
align-items: center;
|
|
@@ -167636,6 +167680,16 @@ const GROUPS = [
|
|
|
167636
167680
|
['route', 'Routes'],
|
|
167637
167681
|
]
|
|
167638
167682
|
|
|
167683
|
+
// The nav renders the features in scannable sections - a section only
|
|
167684
|
+
// shows when the app declares at least one of its resources.
|
|
167685
|
+
const SECTIONS = [
|
|
167686
|
+
['Web', ['site', 'rpc', 'rest', 'route', 'image', 'icon']],
|
|
167687
|
+
['Compute', ['function', 'cron', 'task', 'instance']],
|
|
167688
|
+
['Messaging', ['queue', 'topic', 'subscriber', 'pubsub']],
|
|
167689
|
+
['Storage', ['table', 'cache', 'search', 'store']],
|
|
167690
|
+
['App', ['config', 'auth', 'email', 'worker']],
|
|
167691
|
+
]
|
|
167692
|
+
|
|
167639
167693
|
const svg = inner =>
|
|
167640
167694
|
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">' + inner + '</svg>'
|
|
167641
167695
|
|
|
@@ -168640,19 +168694,37 @@ const render = () => {
|
|
|
168640
168694
|
nav.innerHTML = '<h1>awsless <span>dev</span></h1>'
|
|
168641
168695
|
nav.querySelector('h1').onclick = showHome
|
|
168642
168696
|
|
|
168643
|
-
|
|
168697
|
+
const navButton = kind => {
|
|
168644
168698
|
const count = state.resources.filter(r => r.kind === kind).length
|
|
168645
|
-
if (count === 0)
|
|
168699
|
+
if (count === 0) return null
|
|
168646
168700
|
|
|
168647
168701
|
// The email outbox is a single feed, so a count of registered
|
|
168648
168702
|
// resources would only confuse.
|
|
168649
168703
|
const button = $('button', { className: view.kind === kind ? 'active' : '' }, [
|
|
168650
168704
|
icon(kind),
|
|
168651
|
-
|
|
168705
|
+
groupTitle(kind),
|
|
168652
168706
|
kind === 'email' || kind === 'worker' ? '' : $('span', { className: 'count' }, String(count)),
|
|
168653
168707
|
])
|
|
168654
168708
|
button.onclick = () => selectKind(kind)
|
|
168655
|
-
|
|
168709
|
+
return button
|
|
168710
|
+
}
|
|
168711
|
+
|
|
168712
|
+
const sectioned = new Set(SECTIONS.flatMap(([, kinds]) => kinds))
|
|
168713
|
+
|
|
168714
|
+
for (const [label, kinds] of SECTIONS) {
|
|
168715
|
+
const buttons = kinds.map(navButton).filter(Boolean)
|
|
168716
|
+
if (buttons.length === 0) continue
|
|
168717
|
+
|
|
168718
|
+
nav.append($('h3', {}, label), ...buttons)
|
|
168719
|
+
}
|
|
168720
|
+
|
|
168721
|
+
// A kind without a section still shows, so new features never
|
|
168722
|
+
// silently vanish from the nav.
|
|
168723
|
+
for (const [kind] of GROUPS) {
|
|
168724
|
+
if (sectioned.has(kind)) continue
|
|
168725
|
+
|
|
168726
|
+
const button = navButton(kind)
|
|
168727
|
+
if (button) nav.append(button)
|
|
168656
168728
|
}
|
|
168657
168729
|
|
|
168658
168730
|
if (state.seeds) {
|
|
@@ -169311,6 +169383,7 @@ var startDev = async (props) => {
|
|
|
169311
169383
|
const log = props.onLog ?? (() => {});
|
|
169312
169384
|
const phase = props.phase ?? (async ({ start }, fn) => (log(start), fn(() => {})));
|
|
169313
169385
|
const { appConfig, stackConfigs } = props;
|
|
169386
|
+
useDevBuildDir();
|
|
169314
169387
|
const { builders, appId, ready: ready2 } = createApp({
|
|
169315
169388
|
appConfig,
|
|
169316
169389
|
stackConfigs,
|
|
@@ -169400,10 +169473,12 @@ var startDev = async (props) => {
|
|
|
169400
169473
|
const emitWorkerLine = (line, error3 = false, route) => {
|
|
169401
169474
|
dev.events.emit("worker", { date: Date.now(), line, error: error3, route });
|
|
169402
169475
|
};
|
|
169476
|
+
let seeding = false;
|
|
169403
169477
|
const worker = createBundleWorker({
|
|
169404
169478
|
buildDir,
|
|
169405
169479
|
env: env4,
|
|
169406
169480
|
functionName: bundleName,
|
|
169481
|
+
quiet: () => seeding,
|
|
169407
169482
|
onOutput: (line, stream2, route) => emitWorkerLine(line, stream2 === "stderr", route)
|
|
169408
169483
|
});
|
|
169409
169484
|
dev.resources.push({
|
|
@@ -169480,10 +169555,18 @@ var startDev = async (props) => {
|
|
|
169480
169555
|
});
|
|
169481
169556
|
const seeder = createSeedRunner({ seed: appConfig.seed, env: env4 });
|
|
169482
169557
|
const resetData = createDataReset({ pool: props.pool, stackConfigs });
|
|
169558
|
+
const runSeed = async () => {
|
|
169559
|
+
seeding = true;
|
|
169560
|
+
try {
|
|
169561
|
+
await seeder.run();
|
|
169562
|
+
} finally {
|
|
169563
|
+
seeding = false;
|
|
169564
|
+
}
|
|
169565
|
+
};
|
|
169483
169566
|
if (firstBoot && seeder.enabled && !dirty) {
|
|
169484
169567
|
try {
|
|
169485
169568
|
await phase({ start: "Seeding the local data...", done: "Seeded the local data" }, async () => {
|
|
169486
|
-
await
|
|
169569
|
+
await runSeed();
|
|
169487
169570
|
});
|
|
169488
169571
|
} catch (error3) {
|
|
169489
169572
|
log(`Seeding failed: ${error3 instanceof Error ? error3.message : String(error3)}`);
|
|
@@ -169507,7 +169590,7 @@ var startDev = async (props) => {
|
|
|
169507
169590
|
const dashboard = createDashboardServer({
|
|
169508
169591
|
runSeeds: seeder.enabled ? async () => {
|
|
169509
169592
|
await resetData();
|
|
169510
|
-
await
|
|
169593
|
+
await runSeed();
|
|
169511
169594
|
} : undefined,
|
|
169512
169595
|
app: appConfig.name,
|
|
169513
169596
|
region: appConfig.region,
|
|
@@ -9948,19 +9948,25 @@ import { stringify } from "@awsless/json";
|
|
|
9948
9948
|
import { lambda } from "@awsless/lambda";
|
|
9949
9949
|
import { maxLength, minLength, object, optional, pipe, string, unknown } from "@awsless/validate";
|
|
9950
9950
|
import { getRouteEnv } from "awsless";
|
|
9951
|
-
var
|
|
9952
|
-
|
|
9953
|
-
|
|
9954
|
-
|
|
9955
|
-
|
|
9956
|
-
|
|
9957
|
-
|
|
9958
|
-
|
|
9959
|
-
|
|
9960
|
-
|
|
9961
|
-
|
|
9962
|
-
|
|
9963
|
-
|
|
9951
|
+
var client;
|
|
9952
|
+
var getClient = () => {
|
|
9953
|
+
if (!client || client.status === "end") {
|
|
9954
|
+
client = new import_ioredis.Redis({
|
|
9955
|
+
host: getRouteEnv("REDIS_HOST"),
|
|
9956
|
+
port: Number(getRouteEnv("REDIS_PORT") ?? 6379),
|
|
9957
|
+
tls: getRouteEnv("REDIS_TLS") === "disabled" ? undefined : {},
|
|
9958
|
+
lazyConnect: true,
|
|
9959
|
+
keepAlive: 0,
|
|
9960
|
+
noDelay: true,
|
|
9961
|
+
enableReadyCheck: false,
|
|
9962
|
+
maxRetriesPerRequest: 10,
|
|
9963
|
+
retryStrategy: (times) => times > 20 ? null : Math.min(times * 250, 2000),
|
|
9964
|
+
connectTimeout: 1e4,
|
|
9965
|
+
commandTimeout: 1e4
|
|
9966
|
+
});
|
|
9967
|
+
client.on("error", () => {});
|
|
9968
|
+
}
|
|
9969
|
+
return client;
|
|
9964
9970
|
};
|
|
9965
9971
|
var handle_default = lambda({
|
|
9966
9972
|
schema: object({
|
|
@@ -9968,14 +9974,8 @@ var handle_default = lambda({
|
|
|
9968
9974
|
event: pipe(string(), minLength(1), maxLength(64)),
|
|
9969
9975
|
payload: optional(unknown())
|
|
9970
9976
|
}),
|
|
9971
|
-
async handle({ topic, event, payload }
|
|
9972
|
-
|
|
9973
|
-
ctx.onFinally(() => {
|
|
9974
|
-
return redis.quit().catch(() => {
|
|
9975
|
-
redis.disconnect();
|
|
9976
|
-
});
|
|
9977
|
-
});
|
|
9978
|
-
await redis.publish(getRouteEnv("CHANNEL"), stringify({
|
|
9977
|
+
async handle({ topic, event, payload }) {
|
|
9978
|
+
await getClient().publish(getRouteEnv("CHANNEL"), stringify({
|
|
9979
9979
|
topic,
|
|
9980
9980
|
event,
|
|
9981
9981
|
payload: typeof payload === "undefined" ? undefined : stringify(payload)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@awsless/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
"@awsless/json": "^0.0.11",
|
|
49
49
|
"@awsless/lambda": "^0.0.48",
|
|
50
50
|
"@awsless/s3": "^0.0.22",
|
|
51
|
-
"@awsless/weak-cache": "^0.0.1",
|
|
52
51
|
"@awsless/validate": "^0.2.0",
|
|
53
|
-
"awsless": "^0.1
|
|
52
|
+
"@awsless/weak-cache": "^0.0.1",
|
|
53
|
+
"awsless": "^0.1.4"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@aws-sdk/client-cloudformation": "^3.369.0",
|
|
@@ -108,25 +108,25 @@
|
|
|
108
108
|
"zip-a-folder": "^3.1.6",
|
|
109
109
|
"zod": "^3.24.2",
|
|
110
110
|
"zod-to-json-schema": "^3.24.3",
|
|
111
|
-
"@awsless/big-float": "^0.1.7",
|
|
112
|
-
"@awsless/cloudwatch": "^0.0.1",
|
|
113
111
|
"@awsless/clui": "^0.0.9",
|
|
112
|
+
"@awsless/cloudwatch": "^0.0.1",
|
|
114
113
|
"@awsless/duration": "^0.0.4",
|
|
115
|
-
"@awsless/
|
|
114
|
+
"@awsless/big-float": "^0.1.7",
|
|
116
115
|
"@awsless/iot": "^0.0.5",
|
|
117
|
-
"@awsless/
|
|
116
|
+
"@awsless/dynamodb": "^0.3.23",
|
|
117
|
+
"@awsless/json": "^0.0.11",
|
|
118
118
|
"@awsless/open-search": "^0.0.28",
|
|
119
119
|
"@awsless/redis": "^0.1.13",
|
|
120
|
-
"@awsless/
|
|
120
|
+
"@awsless/s3": "^0.0.22",
|
|
121
121
|
"@awsless/scheduler": "^0.0.5",
|
|
122
|
-
"@awsless/
|
|
122
|
+
"@awsless/size": "^0.0.2",
|
|
123
|
+
"@awsless/lambda": "^0.0.48",
|
|
123
124
|
"@awsless/sqs": "^0.0.24",
|
|
124
|
-
"@awsless/json": "^0.0.11",
|
|
125
|
-
"@awsless/s3": "^0.0.22",
|
|
126
|
-
"@awsless/validate": "^0.2.0",
|
|
127
|
-
"@awsless/weak-cache": "^0.0.1",
|
|
128
125
|
"@awsless/ssm": "^0.0.8",
|
|
129
|
-
"awsless": "^0.
|
|
126
|
+
"@awsless/sns": "^0.0.11",
|
|
127
|
+
"@awsless/weak-cache": "^0.0.1",
|
|
128
|
+
"@awsless/validate": "^0.2.0",
|
|
129
|
+
"awsless": "^0.1.4"
|
|
130
130
|
},
|
|
131
131
|
"scripts": {
|
|
132
132
|
"test": "bun cli/build-handlers.ts && pnpm vitest",
|