@intelligems/sst 2.49.6-ig.8 → 2.49.6-ig.9

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/iot.js CHANGED
@@ -22,6 +22,59 @@ import { useBus } from "./bus.js";
22
22
  import { useProject } from "./project.js";
23
23
  import { useBootstrap } from "./bootstrap.js";
24
24
  import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
25
+ /**
26
+ * Re-sign the next reconnect with credentials that are still alive.
27
+ *
28
+ * The device is built with resolved credential *values*, because
29
+ * `aws-iot-device-sdk` takes strings rather than a provider. It keeps them in
30
+ * closure variables and re-signs the WebSocket URL from those on every
31
+ * reconnect, and nothing ever writes to them again except this call. So once
32
+ * the session expires, every retry presents a dead `sessionToken`, AWS IoT
33
+ * rejects the upgrade, and the socket closes again — forever.
34
+ *
35
+ * Measured on one machine: the connection dropped routinely five times in the
36
+ * first fifteen minutes and recovered each time; an hour later the credentials
37
+ * expired, and the next drop began **93 consecutive failed reconnects over five
38
+ * hours**, none of which emitted an `error` event. Nothing in the CLI said
39
+ * anything, and every request through the Live Lambda bridge 504'd.
40
+ *
41
+ * Every other AWS call in the process is unaffected, because `useAWSClient`
42
+ * passes the *provider* and the SDK calls it per request. This is the one path
43
+ * that holds values, so it is the one path that needs telling.
44
+ *
45
+ * **Why `close` and not `reconnect`.** The signing is synchronous and this
46
+ * refresh is not, so the two race. `emit("reconnect")` runs its handlers and
47
+ * returns — it does not await them — and `_setupStream()` signs on the next
48
+ * line, from whatever the variables hold at that instant. A refresh started
49
+ * there always loses. `close` fires one backoff interval earlier (the SDK
50
+ * manages its own, from `baseReconnectTimeMs` of 1s up to 128s, ignoring the
51
+ * `reconnectPeriod` passed in), which is ample for the resolve to land before
52
+ * the next attempt signs.
53
+ *
54
+ * So this wins the race by margin, not by construction. Two things bound it:
55
+ * `close` fires on **every** failed reconnect, not once per outage, so the
56
+ * values can never be more than one backoff interval stale; and the retry loop
57
+ * is unconditional. Making it airtight would mean keeping the stored
58
+ * credentials warm so the synchronous path can never read a stale one — a
59
+ * timer, which is machinery duplicating what the memoized provider already
60
+ * does. Measured recovery is five seconds, so that is not worth it yet.
61
+ *
62
+ * The provider only reaches the network within five minutes of expiry, so this
63
+ * is an in-memory read on most drops and one real refresh per session.
64
+ */
65
+ async function refreshWebSocketCredentials(device, label) {
66
+ try {
67
+ const fresh = await useAWSCredentials();
68
+ // The typings mark `expiration` as required, but the implementation only
69
+ // assigns the three credential strings and never reads it — so this passes
70
+ // what the provider gave rather than inventing a date to satisfy a
71
+ // parameter nothing uses.
72
+ device.updateWebSocketCredentials(fresh.accessKeyId, fresh.secretAccessKey, fresh.sessionToken, fresh.expiration);
73
+ }
74
+ catch (err) {
75
+ Logger.debug(`${label} credential refresh failed`, err);
76
+ }
77
+ }
25
78
  export const useIOT = lazy(async () => {
26
79
  const bus = useBus();
27
80
  const endpoint = await useIOTEndpoint();
@@ -116,6 +169,7 @@ export const useIOT = lazy(async () => {
116
169
  });
117
170
  device.on("close", () => {
118
171
  Logger.debug("IoT closed");
172
+ void refreshWebSocketCredentials(device, "IoT");
119
173
  });
120
174
  device.on("reconnect", () => {
121
175
  Logger.debug("IoT reconnecting...");
@@ -241,6 +295,7 @@ export const useIOTControl = lazy(async () => {
241
295
  });
242
296
  device.on("close", () => {
243
297
  Logger.debug("IoT control closed");
298
+ void refreshWebSocketCredentials(device, "IoT control");
244
299
  });
245
300
  device.on("reconnect", () => {
246
301
  Logger.debug("IoT control reconnecting...");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "sideEffects": false,
3
3
  "name": "@intelligems/sst",
4
- "version": "2.49.6-ig.8",
4
+ "version": "2.49.6-ig.9",
5
5
  "bin": {
6
6
  "sst": "cli/sst.js"
7
7
  },
@@ -0,0 +1,156 @@
1
+ {
2
+ "publishConfig": {
3
+ "directory": "dist",
4
+ "access": "public"
5
+ },
6
+ "sideEffects": false,
7
+ "name": "@intelligems/sst",
8
+ "version": "2.49.6-ig.9",
9
+ "bin": {
10
+ "sst": "cli/sst.js"
11
+ },
12
+ "description": "A CLI to help deploy SST apps.",
13
+ "type": "module",
14
+ "license": "MIT",
15
+ "scripts": {
16
+ "prepare": "",
17
+ "build": "node build.mjs && tsc",
18
+ "test": "vitest run",
19
+ "dev": "source .env && tsc-watch --onSuccess \"rsync -av dist/* ${TO} --checksum\""
20
+ },
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/sst/v2.git",
24
+ "directory": "packages/cli"
25
+ },
26
+ "exports": {
27
+ "./constructs/deprecated": "./constructs/deprecated/index.js",
28
+ "./constructs/future": "./constructs/future/index.js",
29
+ "./constructs": "./constructs/index.js",
30
+ "./context": "./context/index.js",
31
+ "./node/future/*": "./node/future/*/index.js",
32
+ "./node/*": "./node/*/index.js",
33
+ ".": "./index.js",
34
+ "./*": "./*"
35
+ },
36
+ "homepage": "https://sst.dev",
37
+ "dependencies": {
38
+ "@aws-cdk/aws-lambda-python-alpha": "2.201.0-alpha.0",
39
+ "@aws-cdk/cloud-assembly-schema": "44.5.0",
40
+ "@aws-cdk/cloudformation-diff": "2.182.0",
41
+ "@aws-cdk/cx-api": "2.201.0",
42
+ "@aws-cdk/toolkit-lib": "1.1.1",
43
+ "@aws-crypto/sha256-js": "^5.2.0",
44
+ "@aws-sdk/client-cloudformation": "3.699.0",
45
+ "@aws-sdk/client-ecs": "3.699.0",
46
+ "@aws-sdk/client-eventbridge": "3.699.0",
47
+ "@aws-sdk/client-iam": "3.699.0",
48
+ "@aws-sdk/client-iot": "3.699.0",
49
+ "@aws-sdk/client-iot-data-plane": "3.699.0",
50
+ "@aws-sdk/client-lambda": "3.699.0",
51
+ "@aws-sdk/client-rds-data": "3.699.0",
52
+ "@aws-sdk/client-s3": "3.699.0",
53
+ "@aws-sdk/client-ssm": "3.699.0",
54
+ "@aws-sdk/client-sts": "3.699.0",
55
+ "@aws-sdk/config-resolver": "3.374.0",
56
+ "@aws-sdk/credential-providers": "3.699.0",
57
+ "@aws-sdk/middleware-retry": "3.374.0",
58
+ "@aws-sdk/middleware-signing": "3.451.0",
59
+ "@aws-sdk/signature-v4-crt": "3.451.0",
60
+ "@aws-sdk/smithy-client": "3.374.0",
61
+ "@babel/core": "^7.0.0-0",
62
+ "@babel/generator": "^7.20.5",
63
+ "@babel/plugin-syntax-typescript": "^7.21.4",
64
+ "@smithy/signature-v4": "2.0.16",
65
+ "@trpc/server": "9.18.0",
66
+ "adm-zip": "0.5.14",
67
+ "aws-cdk-lib": "2.201.0",
68
+ "aws-iot-device-sdk": "^2.2.13",
69
+ "aws-sdk": "^2.1501.0",
70
+ "builtin-modules": "3.2.0",
71
+ "cdk-assets": "3.3.1",
72
+ "chalk": "^5.2.0",
73
+ "chokidar": "^3.5.3",
74
+ "ci-info": "^3.7.0",
75
+ "colorette": "^2.0.19",
76
+ "conf": "^10.2.0",
77
+ "constructs": "10.3.0",
78
+ "cross-spawn": "^7.0.3",
79
+ "dendriform-immer-patch-optimiser": "^2.1.0",
80
+ "dotenv": "^16.0.3",
81
+ "esbuild": "0.18.13",
82
+ "express": "^4.18.2",
83
+ "fast-jwt": "^5.0.5",
84
+ "get-port": "^6.1.2",
85
+ "glob": "^10.0.0",
86
+ "graphql": "*",
87
+ "graphql-yoga": "^3.9.0",
88
+ "immer": "9",
89
+ "ink": "^4.0.0",
90
+ "ink-spinner": "^5.0.0",
91
+ "kysely": "^0.25.0",
92
+ "kysely-codegen": "^0.10.1",
93
+ "kysely-data-api": "^0.2.1",
94
+ "minimatch": "^6.1.6",
95
+ "openid-client": "^5.1.8",
96
+ "ora": "^6.1.2",
97
+ "react": "^18.0.0",
98
+ "remeda": "^1.3.0",
99
+ "tree-kill": "^1.2.2",
100
+ "undici": "^5.12.0",
101
+ "uuid": "^9.0.0",
102
+ "ws": "^8.11.0",
103
+ "yargs": "^17.6.2",
104
+ "zod": "^3.21.4"
105
+ },
106
+ "devDependencies": {
107
+ "dotenv-cli": "^8.0.0",
108
+ "@aws-sdk/client-api-gateway": "3.699.0",
109
+ "@aws-sdk/client-cloudfront": "3.699.0",
110
+ "@aws-sdk/client-codebuild": "3.699.0",
111
+ "@aws-sdk/client-sqs": "3.699.0",
112
+ "@aws-sdk/types": "3.451.0",
113
+ "@graphql-tools/merge": "^8.3.16",
114
+ "@sls-next/lambda-at-edge": "^3.7.0",
115
+ "@smithy/types": "4.1.0",
116
+ "@tsconfig/node16": "^1.0.3",
117
+ "@tsconfig/node18": "^18.2.2",
118
+ "@types/adm-zip": "^0.5.0",
119
+ "@types/async": "^3.2.24",
120
+ "@types/aws-iot-device-sdk": "^2.2.8",
121
+ "@types/aws-lambda": "^8.10.128",
122
+ "@types/babel__core": "^7.1.20",
123
+ "@types/babel__generator": "^7.6.4",
124
+ "@types/cross-spawn": "^6.0.2",
125
+ "@types/express": "^4.17.14",
126
+ "@types/node": "22.13.14",
127
+ "@types/react": "^18.0.28",
128
+ "@types/uuid": "^8.3.4",
129
+ "@types/ws": "8.5.3",
130
+ "@types/yargs": "^17.0.13",
131
+ "archiver": "^5.3.1",
132
+ "astro-sst": "2.45.1",
133
+ "async": "^3.2.4",
134
+ "tsx": "^3.12.1",
135
+ "typescript": "5.2.2",
136
+ "vitest": "^0.33.0",
137
+ "tsc-watch": "^6.2.1"
138
+ },
139
+ "peerDependencies": {
140
+ "@sls-next/lambda-at-edge": "^3.7.0"
141
+ },
142
+ "peerDependenciesMeta": {
143
+ "@sls-next/lambda-at-edge": {
144
+ "optional": true
145
+ }
146
+ },
147
+ "bugs": {
148
+ "url": "https://github.com/sst/v2/issues"
149
+ },
150
+ "main": "index.js",
151
+ "directories": {
152
+ "test": "test"
153
+ },
154
+ "keywords": [],
155
+ "author": ""
156
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2020 SST
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.