@auriclabs/jobs-infra 2.1.0 → 2.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @auriclabs/jobs-infra@2.1.0 build /home/runner/work/packages/packages/packages/jobs-infra
2
+ > @auriclabs/jobs-infra@2.2.0 build /home/runner/work/packages/packages/packages/jobs-infra
3
3
  > tsdown src/index.ts --format cjs,esm --dts --tsconfig tsconfig.build.json --no-hash
4
4
 
5
5
  [tsdown] Node.js v20.20.2 is deprecated. Support will be removed in the next minor release. Please upgrade to Node.js 22.18.0 or later.
@@ -7,25 +7,25 @@
7
7
  ℹ entry: src/index.ts
8
8
  ℹ tsconfig: tsconfig.build.json
9
9
  ℹ Build start
10
- ℹ [CJS] dist/index.cjs 5.43 kB │ gzip: 2.21 kB
11
- ℹ [CJS] 1 files, total: 5.43 kB
12
- ℹ [CJS] dist/index.d.cts.map 1.06 kB │ gzip: 0.43 kB
13
- ℹ [CJS] dist/index.d.cts 3.21 kB │ gzip: 1.30 kB
14
- ℹ [CJS] 2 files, total: 4.27 kB
10
+ ℹ [CJS] dist/index.cjs 5.47 kB │ gzip: 2.23 kB
11
+ ℹ [CJS] 1 files, total: 5.47 kB
12
+ ℹ [CJS] dist/index.d.cts.map 1.35 kB │ gzip: 0.51 kB
13
+ ℹ [CJS] dist/index.d.cts 5.09 kB │ gzip: 1.99 kB
14
+ ℹ [CJS] 2 files, total: 6.43 kB
15
15
  [PLUGIN_TIMINGS] Warning: Your build spent significant time in plugins. Here is a breakdown:
16
- - rolldown-plugin-dts:generate (55%)
17
- - tsdown:deps (44%)
16
+ - rolldown-plugin-dts:generate (69%)
17
+ - tsdown:deps (30%)
18
18
  See https://rolldown.rs/options/checks#plugintimings for more details.
19
19
 
20
- ✔ Build complete in 5776ms
21
- ℹ [ESM] dist/index.mjs  4.22 kB │ gzip: 1.75 kB
22
- ℹ [ESM] dist/index.mjs.map 11.40 kB │ gzip: 4.08 kB
23
- ℹ [ESM] dist/index.d.mts.map  1.06 kB │ gzip: 0.43 kB
24
- ℹ [ESM] dist/index.d.mts  3.21 kB │ gzip: 1.30 kB
25
- ℹ [ESM] 4 files, total: 19.89 kB
20
+ ✔ Build complete in 6061ms
21
+ ℹ [ESM] dist/index.mjs  4.25 kB │ gzip: 1.77 kB
22
+ ℹ [ESM] dist/index.mjs.map 13.35 kB │ gzip: 4.78 kB
23
+ ℹ [ESM] dist/index.d.mts.map  1.35 kB │ gzip: 0.51 kB
24
+ ℹ [ESM] dist/index.d.mts  5.09 kB │ gzip: 1.99 kB
25
+ ℹ [ESM] 4 files, total: 24.03 kB
26
26
  [PLUGIN_TIMINGS] Warning: Your build spent significant time in plugins. Here is a breakdown:
27
- - rolldown-plugin-dts:generate (80%)
28
- - tsdown:deps (19%)
27
+ - rolldown-plugin-dts:generate (84%)
28
+ - tsdown:deps (16%)
29
29
  See https://rolldown.rs/options/checks#plugintimings for more details.
30
30
 
31
- ✔ Build complete in 5779ms
31
+ ✔ Build complete in 6063ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @auriclabs/jobs-infra
2
2
 
3
+ ## 2.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - dd6d044: Take the `sst` components namespace as an explicit parameter in `createJobTable` and
8
+ `createJobsDashboard` instead of referencing the injected `sst` global.
9
+
10
+ `@auriclabs/jobs-infra` ships as ESM (`dist/index.mjs`). SST's config evaluator injects the `sst`
11
+ global into config source through an esbuild `onLoad` plugin whose filter is
12
+ `\.(js|ts|jsx|tsx)# @auriclabs/jobs-infra, which deliberately skips `.mjs`/`.cjs`. (`$app` / `$jsonStringify`/`$output`arrive via esbuild`Define`/`Inject`, which are extension-agnostic and keep working — only the `sst`namespace and`@pulumi/\*`provider aliases come from the skipped`onLoad`channel.) A bare`sst.aws.Dynamo`reference in the`.mjs`build therefore threw`ReferenceError:
13
+ sst is not
14
+ defined`at deploy time. Passing`sst`in as a parameter — as`@auriclabs/migrations`' `createTable(sst)`
15
+ already does — sidesteps the injection entirely.
16
+
17
+ Breaking:
18
+ - `createJobTable(name)` → `createJobTable(sst, name)`
19
+ - `createJobsDashboard(options)` now requires `options.sst`
20
+
21
+ `registerJobResources` is unchanged: it only uses `$jsonStringify` (an `Inject` global that works
22
+ in `.mjs`) plus caller-supplied resources.
23
+
3
24
  ## 2.1.0
4
25
 
5
26
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -25,7 +25,7 @@ let node_module = require("node:module");
25
25
  let node_path = require("node:path");
26
26
  node_path = __toESM(node_path);
27
27
  //#region src/job-table.ts
28
- function createJobTable(name) {
28
+ function createJobTable(sst, name) {
29
29
  return new sst.aws.Dynamo(name, {
30
30
  fields: {
31
31
  pk: "string",
@@ -101,6 +101,7 @@ function registerJobResources(config) {
101
101
  //#endregion
102
102
  //#region src/dashboard.ts
103
103
  function createJobsDashboard(options) {
104
+ const { sst } = options;
104
105
  const api = new sst.aws.ApiGatewayV2("JobsDashboardApi", { cors: true });
105
106
  const link = [options.table, ...options.link ?? []];
106
107
  api.route("$default", {
package/dist/index.d.cts CHANGED
@@ -1,7 +1,27 @@
1
1
  import { FunctionWithName } from "@auriclabs/sst-utils";
2
2
 
3
3
  //#region src/job-table.d.ts
4
- declare function createJobTable(name: string): sst.aws.Dynamo;
4
+ /**
5
+ * The subset of the SST components namespace that {@link createJobTable} needs
6
+ * at runtime.
7
+ *
8
+ * `@auriclabs/jobs-infra` ships as ESM (`dist/index.mjs`). SST's config
9
+ * evaluator injects the `sst` global into config source via an esbuild
10
+ * `onLoad` plugin whose filter is `\.(js|ts|jsx|tsx)$` — it deliberately skips
11
+ * `.mjs`/`.cjs`. (The `$app` / `$jsonStringify` / `$output` globals arrive via
12
+ * esbuild `Define`/`Inject`, which are extension-agnostic, so those keep
13
+ * working; only the `sst` namespace and the `@pulumi/*` provider aliases come
14
+ * from the skipped `onLoad` channel.) A bare `sst.aws.Dynamo` reference in this
15
+ * `.mjs` file therefore throws `ReferenceError: sst is not defined` at deploy
16
+ * time. Taking `sst` as a parameter — exactly as `@auriclabs/migrations`'
17
+ * `createTable(sst)` does — sidesteps the injection entirely.
18
+ */
19
+ interface JobTableSstProvider {
20
+ aws: {
21
+ Dynamo: typeof sst.aws.Dynamo;
22
+ };
23
+ }
24
+ declare function createJobTable(sst: JobTableSstProvider, name: string): sst.aws.Dynamo;
5
25
  //#endregion
6
26
  //#region src/job-resources.d.ts
7
27
  interface LambdaJobResource {
@@ -45,7 +65,29 @@ interface JobsDashboardBasicAuthConfig {
45
65
  /** Realm shown in browser auth dialog. Defaults to "Jobs Dashboard". */
46
66
  realm?: string;
47
67
  }
68
+ /**
69
+ * The subset of the SST components namespace that {@link createJobsDashboard}
70
+ * needs at runtime.
71
+ *
72
+ * Passed in rather than referenced as the `sst` global for the same reason as
73
+ * {@link JobTableSstProvider}: this package ships as `.mjs`, and SST's config
74
+ * evaluator skips `.mjs`/`.cjs` when injecting the `sst` global (its esbuild
75
+ * `onLoad` plugin filters on `\.(js|ts|jsx|tsx)$`). See the note on
76
+ * {@link JobTableSstProvider} for the full mechanism.
77
+ */
78
+ interface JobsDashboardSstProvider {
79
+ aws: {
80
+ ApiGatewayV2: typeof sst.aws.ApiGatewayV2;
81
+ StaticSite: typeof sst.aws.StaticSite;
82
+ };
83
+ }
48
84
  interface JobsDashboardOptions {
85
+ /**
86
+ * SST components namespace — pass the injected `sst` global from your
87
+ * `sst.config.ts` (a `.ts` file, which SST *does* inject `sst` into).
88
+ * See {@link JobsDashboardSstProvider}.
89
+ */
90
+ sst: JobsDashboardSstProvider;
49
91
  /**
50
92
  * Handler path for the dashboard API Lambda. The handler should call
51
93
  * `initJobs({ tableName: Resource.<JobTable>.name })` and export
@@ -81,5 +123,5 @@ declare function createJobsDashboard(options: JobsDashboardOptions): {
81
123
  site: sst.aws.StaticSite;
82
124
  };
83
125
  //#endregion
84
- export { InProcessJobResource, JobResource, JobsDashboardBasicAuthConfig, JobsDashboardOptions, LambdaJobResource, RegisterJobResourcesConfig, WorkerJobResource, createJobTable, createJobsDashboard, registerJobResources };
126
+ export { InProcessJobResource, JobResource, JobTableSstProvider, JobsDashboardBasicAuthConfig, JobsDashboardOptions, JobsDashboardSstProvider, LambdaJobResource, RegisterJobResourcesConfig, WorkerJobResource, createJobTable, createJobsDashboard, registerJobResources };
85
127
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/job-table.ts","../src/job-resources.ts","../src/dashboard.ts"],"mappings":";;;iBAAgB,cAAA,CAAe,IAAA,WAAY,GAAA,CAAA,GAAA,CAAA,MAAA;;;UCE1B,iBAAA;EACf,EAAA;EACA,QAAA;EACA,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA;EACf,GAAA,EAAK,gBAAA;AAAA;AAAA,UAGU,oBAAA;EACf,EAAA;EACA,QAAA;EACA,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA;EDZ0B;ECczC,OAAA;;EAEA,IAAA;EACA,WAAA,GAAc,MAAA;AAAA;AAAA,UAGC,iBAAA;EACf,EAAA;EACA,QAAA;EACA,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA;AAAA;AAAA,KAGL,WAAA,GAAc,iBAAA,GAAoB,oBAAA,GAAuB,iBAAA;AAAA,UAEpD,0BAAA;EACf,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,MAAA;EACf,SAAA,EAAW,WAAA;EACX,YAAA;IACE,MAAA;IACA,QAAA;EAAA;AAAA;AAAA,iBAIY,oBAAA,CAAqB,MAAA,EAAQ,0BAAA;;;UClC5B,4BAAA;;EAEf,QAAA,EAAU,KAAA,CAAM,KAAA;EFLF;EEOd,QAAA,EAAU,KAAA,CAAM,KAAA;;EAEhB,KAAA;AAAA;AAAA,UAGe,oBAAA;EFZ0B;;;;;EEkBzC,UAAA;;EAEA,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,MAAA;EDlBiB;ECoBhC,IAAA;EACA,MAAA,GAAS,GAAA,CAAI,GAAA,CAAI,cAAA;EDpBjB;;;;ECyBA,MAAA;EDvBe;;;;;AAIjB;;;;;;;ECgCE,SAAA,GAAY,4BAAA;AAAA;AAAA,iBAGE,mBAAA,CAAoB,OAAA,EAAS,oBAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/job-table.ts","../src/job-resources.ts","../src/dashboard.ts"],"mappings":";;;;;;AAeA;;;;;;;;;;;AAMA;UANiB,mBAAA;EACf,GAAA;IACE,MAAA,SAAe,GAAA,CAAI,GAAA,CAAI,MAAA;EAAA;AAAA;AAAA,iBAIX,cAAA,CAAe,GAAA,EAAK,mBAAA,EAAqB,IAAA,WAAY,GAAA,CAAA,GAAA,CAAA,MAAA;;;UCnBpD,iBAAA;EACf,EAAA;EACA,QAAA;EACA,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA;EACf,GAAA,EAAK,gBAAA;AAAA;AAAA,UAGU,oBAAA;EACf,EAAA;EACA,QAAA;EACA,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA;EDKU;ECHzB,OAAA;EDG+B;ECD/B,IAAA;EACA,WAAA,GAAc,MAAA;AAAA;AAAA,UAGC,iBAAA;EACf,EAAA;EACA,QAAA;EACA,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA;AAAA;AAAA,KAGL,WAAA,GAAc,iBAAA,GAAoB,oBAAA,GAAuB,iBAAA;AAAA,UAEpD,0BAAA;EACf,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,MAAA;EACf,SAAA,EAAW,WAAA;EACX,YAAA;IACE,MAAA;IACA,QAAA;EAAA;AAAA;AAAA,iBAIY,oBAAA,CAAqB,MAAA,EAAQ,0BAAA;;;UClC5B,4BAAA;;EAEf,QAAA,EAAU,KAAA,CAAM,KAAA;EFUD;EERf,QAAA,EAAU,KAAA,CAAM,KAAA;;EAEhB,KAAA;AAAA;;;;;;;AFYF;;;;UECiB,wBAAA;EACf,GAAA;IACE,YAAA,SAAqB,GAAA,CAAI,GAAA,CAAI,YAAA;IAC7B,UAAA,SAAmB,GAAA,CAAI,GAAA,CAAI,UAAA;EAAA;AAAA;AAAA,UAId,oBAAA;EFRoD;;;;ACnBrE;ECiCE,GAAA,EAAK,wBAAA;;;;;;EAML,UAAA;EDpCW;ECsCX,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,MAAA;EDrCf;ECuCA,IAAA;EACA,MAAA,GAAS,GAAA,CAAI,GAAA,CAAI,cAAA;EDxCI;AAGvB;;;EC0CE,MAAA;EDzCA;;;;;;;;;;;;ECsDA,SAAA,GAAY,4BAAA;AAAA;AAAA,iBAGE,mBAAA,CAAoB,OAAA,EAAS,oBAAA"}
package/dist/index.d.mts CHANGED
@@ -1,7 +1,27 @@
1
1
  import { FunctionWithName } from "@auriclabs/sst-utils";
2
2
 
3
3
  //#region src/job-table.d.ts
4
- declare function createJobTable(name: string): sst.aws.Dynamo;
4
+ /**
5
+ * The subset of the SST components namespace that {@link createJobTable} needs
6
+ * at runtime.
7
+ *
8
+ * `@auriclabs/jobs-infra` ships as ESM (`dist/index.mjs`). SST's config
9
+ * evaluator injects the `sst` global into config source via an esbuild
10
+ * `onLoad` plugin whose filter is `\.(js|ts|jsx|tsx)$` — it deliberately skips
11
+ * `.mjs`/`.cjs`. (The `$app` / `$jsonStringify` / `$output` globals arrive via
12
+ * esbuild `Define`/`Inject`, which are extension-agnostic, so those keep
13
+ * working; only the `sst` namespace and the `@pulumi/*` provider aliases come
14
+ * from the skipped `onLoad` channel.) A bare `sst.aws.Dynamo` reference in this
15
+ * `.mjs` file therefore throws `ReferenceError: sst is not defined` at deploy
16
+ * time. Taking `sst` as a parameter — exactly as `@auriclabs/migrations`'
17
+ * `createTable(sst)` does — sidesteps the injection entirely.
18
+ */
19
+ interface JobTableSstProvider {
20
+ aws: {
21
+ Dynamo: typeof sst.aws.Dynamo;
22
+ };
23
+ }
24
+ declare function createJobTable(sst: JobTableSstProvider, name: string): sst.aws.Dynamo;
5
25
  //#endregion
6
26
  //#region src/job-resources.d.ts
7
27
  interface LambdaJobResource {
@@ -45,7 +65,29 @@ interface JobsDashboardBasicAuthConfig {
45
65
  /** Realm shown in browser auth dialog. Defaults to "Jobs Dashboard". */
46
66
  realm?: string;
47
67
  }
68
+ /**
69
+ * The subset of the SST components namespace that {@link createJobsDashboard}
70
+ * needs at runtime.
71
+ *
72
+ * Passed in rather than referenced as the `sst` global for the same reason as
73
+ * {@link JobTableSstProvider}: this package ships as `.mjs`, and SST's config
74
+ * evaluator skips `.mjs`/`.cjs` when injecting the `sst` global (its esbuild
75
+ * `onLoad` plugin filters on `\.(js|ts|jsx|tsx)$`). See the note on
76
+ * {@link JobTableSstProvider} for the full mechanism.
77
+ */
78
+ interface JobsDashboardSstProvider {
79
+ aws: {
80
+ ApiGatewayV2: typeof sst.aws.ApiGatewayV2;
81
+ StaticSite: typeof sst.aws.StaticSite;
82
+ };
83
+ }
48
84
  interface JobsDashboardOptions {
85
+ /**
86
+ * SST components namespace — pass the injected `sst` global from your
87
+ * `sst.config.ts` (a `.ts` file, which SST *does* inject `sst` into).
88
+ * See {@link JobsDashboardSstProvider}.
89
+ */
90
+ sst: JobsDashboardSstProvider;
49
91
  /**
50
92
  * Handler path for the dashboard API Lambda. The handler should call
51
93
  * `initJobs({ tableName: Resource.<JobTable>.name })` and export
@@ -81,5 +123,5 @@ declare function createJobsDashboard(options: JobsDashboardOptions): {
81
123
  site: sst.aws.StaticSite;
82
124
  };
83
125
  //#endregion
84
- export { InProcessJobResource, JobResource, JobsDashboardBasicAuthConfig, JobsDashboardOptions, LambdaJobResource, RegisterJobResourcesConfig, WorkerJobResource, createJobTable, createJobsDashboard, registerJobResources };
126
+ export { InProcessJobResource, JobResource, JobTableSstProvider, JobsDashboardBasicAuthConfig, JobsDashboardOptions, JobsDashboardSstProvider, LambdaJobResource, RegisterJobResourcesConfig, WorkerJobResource, createJobTable, createJobsDashboard, registerJobResources };
85
127
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/job-table.ts","../src/job-resources.ts","../src/dashboard.ts"],"mappings":";;;iBAAgB,cAAA,CAAe,IAAA,WAAY,GAAA,CAAA,GAAA,CAAA,MAAA;;;UCE1B,iBAAA;EACf,EAAA;EACA,QAAA;EACA,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA;EACf,GAAA,EAAK,gBAAA;AAAA;AAAA,UAGU,oBAAA;EACf,EAAA;EACA,QAAA;EACA,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA;EDZ0B;ECczC,OAAA;;EAEA,IAAA;EACA,WAAA,GAAc,MAAA;AAAA;AAAA,UAGC,iBAAA;EACf,EAAA;EACA,QAAA;EACA,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA;AAAA;AAAA,KAGL,WAAA,GAAc,iBAAA,GAAoB,oBAAA,GAAuB,iBAAA;AAAA,UAEpD,0BAAA;EACf,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,MAAA;EACf,SAAA,EAAW,WAAA;EACX,YAAA;IACE,MAAA;IACA,QAAA;EAAA;AAAA;AAAA,iBAIY,oBAAA,CAAqB,MAAA,EAAQ,0BAAA;;;UClC5B,4BAAA;;EAEf,QAAA,EAAU,KAAA,CAAM,KAAA;EFLF;EEOd,QAAA,EAAU,KAAA,CAAM,KAAA;;EAEhB,KAAA;AAAA;AAAA,UAGe,oBAAA;EFZ0B;;;;;EEkBzC,UAAA;;EAEA,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,MAAA;EDlBiB;ECoBhC,IAAA;EACA,MAAA,GAAS,GAAA,CAAI,GAAA,CAAI,cAAA;EDpBjB;;;;ECyBA,MAAA;EDvBe;;;;;AAIjB;;;;;;;ECgCE,SAAA,GAAY,4BAAA;AAAA;AAAA,iBAGE,mBAAA,CAAoB,OAAA,EAAS,oBAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/job-table.ts","../src/job-resources.ts","../src/dashboard.ts"],"mappings":";;;;;;AAeA;;;;;;;;;;;AAMA;UANiB,mBAAA;EACf,GAAA;IACE,MAAA,SAAe,GAAA,CAAI,GAAA,CAAI,MAAA;EAAA;AAAA;AAAA,iBAIX,cAAA,CAAe,GAAA,EAAK,mBAAA,EAAqB,IAAA,WAAY,GAAA,CAAA,GAAA,CAAA,MAAA;;;UCnBpD,iBAAA;EACf,EAAA;EACA,QAAA;EACA,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA;EACf,GAAA,EAAK,gBAAA;AAAA;AAAA,UAGU,oBAAA;EACf,EAAA;EACA,QAAA;EACA,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA;EDKU;ECHzB,OAAA;EDG+B;ECD/B,IAAA;EACA,WAAA,GAAc,MAAA;AAAA;AAAA,UAGC,iBAAA;EACf,EAAA;EACA,QAAA;EACA,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,KAAA;AAAA;AAAA,KAGL,WAAA,GAAc,iBAAA,GAAoB,oBAAA,GAAuB,iBAAA;AAAA,UAEpD,0BAAA;EACf,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,MAAA;EACf,SAAA,EAAW,WAAA;EACX,YAAA;IACE,MAAA;IACA,QAAA;EAAA;AAAA;AAAA,iBAIY,oBAAA,CAAqB,MAAA,EAAQ,0BAAA;;;UClC5B,4BAAA;;EAEf,QAAA,EAAU,KAAA,CAAM,KAAA;EFUD;EERf,QAAA,EAAU,KAAA,CAAM,KAAA;;EAEhB,KAAA;AAAA;;;;;;;AFYF;;;;UECiB,wBAAA;EACf,GAAA;IACE,YAAA,SAAqB,GAAA,CAAI,GAAA,CAAI,YAAA;IAC7B,UAAA,SAAmB,GAAA,CAAI,GAAA,CAAI,UAAA;EAAA;AAAA;AAAA,UAId,oBAAA;EFRoD;;;;ACnBrE;ECiCE,GAAA,EAAK,wBAAA;;;;;;EAML,UAAA;EDpCW;ECsCX,KAAA,EAAO,GAAA,CAAI,GAAA,CAAI,MAAA;EDrCf;ECuCA,IAAA;EACA,MAAA,GAAS,GAAA,CAAI,GAAA,CAAI,cAAA;EDxCI;AAGvB;;;EC0CE,MAAA;EDzCA;;;;;;;;;;;;ECsDA,SAAA,GAAY,4BAAA;AAAA;AAAA,iBAGE,mBAAA,CAAoB,OAAA,EAAS,oBAAA"}
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from "node:module";
2
2
  import path from "node:path";
3
3
  //#region src/job-table.ts
4
- function createJobTable(name) {
4
+ function createJobTable(sst, name) {
5
5
  return new sst.aws.Dynamo(name, {
6
6
  fields: {
7
7
  pk: "string",
@@ -77,6 +77,7 @@ function registerJobResources(config) {
77
77
  //#endregion
78
78
  //#region src/dashboard.ts
79
79
  function createJobsDashboard(options) {
80
+ const { sst } = options;
80
81
  const api = new sst.aws.ApiGatewayV2("JobsDashboardApi", { cors: true });
81
82
  const link = [options.table, ...options.link ?? []];
82
83
  api.route("$default", {
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/job-table.ts","../src/job-resources.ts","../src/dashboard.ts"],"sourcesContent":["export function createJobTable(name: string) {\n return new sst.aws.Dynamo(name, {\n fields: {\n pk: 'string',\n sk: 'string',\n numberIndexPk: 'string',\n numberIndexSk: 'number',\n gsi1pk: 'string',\n gsi1sk: 'string',\n },\n primaryIndex: {\n hashKey: 'pk',\n rangeKey: 'sk',\n },\n globalIndexes: {\n numberIndex: { hashKey: 'numberIndexPk', rangeKey: 'numberIndexSk' },\n gsi1: { hashKey: 'gsi1pk', rangeKey: 'gsi1sk' },\n },\n stream: 'new-and-old-images',\n });\n}\n","import { FunctionWithName } from '@auriclabs/sst-utils';\n\nexport interface LambdaJobResource {\n id: string;\n executor: 'lambda';\n queue: sst.aws.Queue;\n fns: FunctionWithName[];\n}\n\nexport interface InProcessJobResource {\n id: string;\n executor: 'in-process';\n queue: sst.aws.Queue;\n /** Path to a handler that wraps createRegistryExecutorHandler(...) from @auriclabs/jobs. */\n handler: string;\n /** Extra linkables the in-process handlers depend on. */\n link?: unknown[];\n environment?: Record<string, string>;\n}\n\nexport interface WorkerJobResource {\n id: string;\n executor?: never;\n queue: sst.aws.Queue;\n}\n\nexport type JobResource = LambdaJobResource | InProcessJobResource | WorkerJobResource;\n\nexport interface RegisterJobResourcesConfig {\n table: sst.aws.Dynamo;\n resources: JobResource[];\n handlerPaths: {\n stream: string;\n executor: string;\n };\n}\n\nexport function registerJobResources(config: RegisterJobResourcesConfig) {\n const { table, resources, handlerPaths } = config;\n const QUEUE_URL_LIST = $jsonStringify(resources.map(({ id, queue }) => [id, queue.url]));\n\n table.subscribe(\n 'JobTableStream',\n {\n handler: handlerPaths.stream,\n link: [table, ...resources.map(({ queue }) => queue)],\n environment: {\n QUEUE_URL_LIST,\n },\n },\n {\n filters: [\n {\n dynamodb: {\n NewImage: {\n __edb_e__: {\n S: ['job-attempt'],\n },\n },\n },\n },\n {\n dynamodb: {\n OldImage: {\n __edb_e__: {\n S: ['job-attempt'],\n },\n },\n },\n },\n ],\n },\n );\n\n resources.forEach((resource) => {\n if (!('executor' in resource)) {\n return;\n }\n\n if (resource.executor === 'lambda') {\n resource.queue.subscribe(\n {\n handler: handlerPaths.executor,\n link: [table, resource.queue, ...resource.fns],\n environment: {\n LAMBDA_FUNCTION_LIST: $jsonStringify(resource.fns.map((f) => [f.name, f.arn])),\n // needed for startJob's scheduledAt re-enqueue\n QUEUE_URL_LIST,\n },\n },\n {\n batch: {\n size: 10,\n window: '3 seconds',\n partialResponses: true,\n },\n },\n );\n }\n\n if (resource.executor === 'in-process') {\n resource.queue.subscribe(\n {\n handler: resource.handler,\n link: [table, resource.queue, ...(resource.link ?? [])],\n environment: {\n ...resource.environment,\n // in-process executors re-enqueue for scheduledAt deferrals and\n // continuations — must win over consumer-provided environment\n QUEUE_URL_LIST,\n },\n },\n {\n batch: {\n size: 10,\n window: '3 seconds',\n partialResponses: true,\n },\n },\n );\n }\n });\n}\n","import { createRequire } from 'node:module';\nimport path from 'node:path';\n\nexport interface JobsDashboardBasicAuthConfig {\n /** Plaintext username — typically wired from an SST secret. */\n username: $util.Input<string>;\n /** Plaintext password — typically wired from an SST secret. */\n password: $util.Input<string>;\n /** Realm shown in browser auth dialog. Defaults to \"Jobs Dashboard\". */\n realm?: string;\n}\n\nexport interface JobsDashboardOptions {\n /**\n * Handler path for the dashboard API Lambda. The handler should call\n * `initJobs({ tableName: Resource.<JobTable>.name })` and export\n * `createJobsDashboardApiHandler()` from `@auriclabs/jobs`.\n */\n apiHandler: string;\n /** Job table — linked into the API function. */\n table: sst.aws.Dynamo;\n /** Extra linkables for the API function (beyond the table). */\n link?: unknown[];\n domain?: sst.aws.StaticSiteArgs['domain'];\n /**\n * Override the path to the `@auriclabs/jobs` package's `ui/` directory.\n * Defaults to resolving the installed package via `require.resolve`.\n */\n uiPath?: string;\n /**\n * Optional HTTP basic auth gate on the static site. When set, injects a\n * basic-auth check into the StaticSite's CloudFront viewer-request\n * function — requests without the matching `Authorization: Basic <base64>`\n * header get a 401 before any routing logic runs. Credentials are inlined\n * into the function source at deploy time via Pulumi apply.\n *\n * Note: this only gates the static UI. The API gateway URL remains\n * directly callable — browsers don't auto-send basic auth credentials\n * cross-origin, so the dashboard's fetch() can't carry them. Treat this\n * as discovery-prevention for the dashboard, not API protection.\n */\n basicAuth?: JobsDashboardBasicAuthConfig;\n}\n\nexport function createJobsDashboard(options: JobsDashboardOptions) {\n const api = new sst.aws.ApiGatewayV2('JobsDashboardApi', { cors: true });\n\n const link: unknown[] = [options.table, ...(options.link ?? [])];\n\n api.route('$default', {\n handler: options.apiHandler,\n link,\n });\n\n const uiPath = options.uiPath ?? resolveJobsUiPath();\n const uiRelative = path.relative(process.cwd(), uiPath);\n\n const basicAuthInjection = options.basicAuth\n ? buildBasicAuthInjection(options.basicAuth)\n : undefined;\n\n // Copy pre-built dist and inject the API URL at deploy time.\n // The build command copies ui/dist to a temp output dir and injects\n // a script tag that sets globalThis.__JOBS_API_URL__ before the app loads.\n const site = new sst.aws.StaticSite('JobsDashboard', {\n path: uiRelative,\n build: {\n command: [\n // _deploy persists in node_modules across deploys — a stale copy would\n // nest the new dist and keep serving the old bundle\n 'rm -rf _deploy',\n 'cp -r dist _deploy',\n `sed -i.bak 's|<head>|<head><script>globalThis.__JOBS_API_URL__=\"'$VITE_API_URL'\"</script>|' _deploy/index.html`,\n 'rm -f _deploy/index.html.bak',\n ].join(' && '),\n output: '_deploy',\n },\n dev: {\n command: 'npx vite dev',\n url: 'http://localhost:3101',\n },\n environment: {\n VITE_API_URL: api.url,\n },\n domain: options.domain,\n ...(basicAuthInjection && {\n edge: {\n viewerRequest: { injection: basicAuthInjection },\n },\n }),\n });\n\n return { api, site };\n}\n\n/**\n * Resolve the `@auriclabs/jobs` package's `ui/` directory. jobs-infra is a\n * separate package, so the UI ships with `@auriclabs/jobs` — resolve it\n * through the consumer's node_modules (the workspace link covers local dev).\n */\nfunction resolveJobsUiPath(): string {\n const require = createRequire(import.meta.url);\n const pkgJsonPath = require.resolve('@auriclabs/jobs/package.json');\n const pkgRoot = path.dirname(pkgJsonPath);\n return path.join(pkgRoot, 'ui');\n}\n\nfunction buildBasicAuthInjection(auth: JobsDashboardBasicAuthConfig) {\n const realm = (auth.realm ?? 'Jobs Dashboard').replace(/\"/g, '\\\\\"');\n\n // Inline the encoded credential into the CloudFront Function source at\n // deploy time. CFFs can't read SSM at runtime, so the credential lives\n // in the deployed function's code (same trust boundary as SST secret\n // state). Rotate by updating the upstream secret and redeploying.\n //\n // Returned as an injection string that SST splices into the start of\n // its existing `cloudfront-js-2.0` viewer-request handler — a 401\n // return short-circuits the rest of the routing logic.\n return $output([auth.username, auth.password]).apply(([username, password]) => {\n const encoded = Buffer.from(`${username}:${password}`).toString('base64');\n return [\n 'var __auth = event.request.headers.authorization && event.request.headers.authorization.value;',\n `if (__auth !== \"Basic ${encoded}\") {`,\n ' return {',\n ' statusCode: 401,',\n ' statusDescription: \"Unauthorized\",',\n ' headers: {',\n ` \"www-authenticate\": { value: 'Basic realm=\"${realm}\"' }`,\n ' }',\n ' };',\n '}',\n ].join('\\n');\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/job-table.ts","../src/job-resources.ts","../src/dashboard.ts"],"sourcesContent":["/**\n * The subset of the SST components namespace that {@link createJobTable} needs\n * at runtime.\n *\n * `@auriclabs/jobs-infra` ships as ESM (`dist/index.mjs`). SST's config\n * evaluator injects the `sst` global into config source via an esbuild\n * `onLoad` plugin whose filter is `\\.(js|ts|jsx|tsx)$` — it deliberately skips\n * `.mjs`/`.cjs`. (The `$app` / `$jsonStringify` / `$output` globals arrive via\n * esbuild `Define`/`Inject`, which are extension-agnostic, so those keep\n * working; only the `sst` namespace and the `@pulumi/*` provider aliases come\n * from the skipped `onLoad` channel.) A bare `sst.aws.Dynamo` reference in this\n * `.mjs` file therefore throws `ReferenceError: sst is not defined` at deploy\n * time. Taking `sst` as a parameter — exactly as `@auriclabs/migrations`'\n * `createTable(sst)` does — sidesteps the injection entirely.\n */\nexport interface JobTableSstProvider {\n aws: {\n Dynamo: typeof sst.aws.Dynamo;\n };\n}\n\nexport function createJobTable(sst: JobTableSstProvider, name: string) {\n return new sst.aws.Dynamo(name, {\n fields: {\n pk: 'string',\n sk: 'string',\n numberIndexPk: 'string',\n numberIndexSk: 'number',\n gsi1pk: 'string',\n gsi1sk: 'string',\n },\n primaryIndex: {\n hashKey: 'pk',\n rangeKey: 'sk',\n },\n globalIndexes: {\n numberIndex: { hashKey: 'numberIndexPk', rangeKey: 'numberIndexSk' },\n gsi1: { hashKey: 'gsi1pk', rangeKey: 'gsi1sk' },\n },\n stream: 'new-and-old-images',\n });\n}\n","import { FunctionWithName } from '@auriclabs/sst-utils';\n\nexport interface LambdaJobResource {\n id: string;\n executor: 'lambda';\n queue: sst.aws.Queue;\n fns: FunctionWithName[];\n}\n\nexport interface InProcessJobResource {\n id: string;\n executor: 'in-process';\n queue: sst.aws.Queue;\n /** Path to a handler that wraps createRegistryExecutorHandler(...) from @auriclabs/jobs. */\n handler: string;\n /** Extra linkables the in-process handlers depend on. */\n link?: unknown[];\n environment?: Record<string, string>;\n}\n\nexport interface WorkerJobResource {\n id: string;\n executor?: never;\n queue: sst.aws.Queue;\n}\n\nexport type JobResource = LambdaJobResource | InProcessJobResource | WorkerJobResource;\n\nexport interface RegisterJobResourcesConfig {\n table: sst.aws.Dynamo;\n resources: JobResource[];\n handlerPaths: {\n stream: string;\n executor: string;\n };\n}\n\nexport function registerJobResources(config: RegisterJobResourcesConfig) {\n const { table, resources, handlerPaths } = config;\n const QUEUE_URL_LIST = $jsonStringify(resources.map(({ id, queue }) => [id, queue.url]));\n\n table.subscribe(\n 'JobTableStream',\n {\n handler: handlerPaths.stream,\n link: [table, ...resources.map(({ queue }) => queue)],\n environment: {\n QUEUE_URL_LIST,\n },\n },\n {\n filters: [\n {\n dynamodb: {\n NewImage: {\n __edb_e__: {\n S: ['job-attempt'],\n },\n },\n },\n },\n {\n dynamodb: {\n OldImage: {\n __edb_e__: {\n S: ['job-attempt'],\n },\n },\n },\n },\n ],\n },\n );\n\n resources.forEach((resource) => {\n if (!('executor' in resource)) {\n return;\n }\n\n if (resource.executor === 'lambda') {\n resource.queue.subscribe(\n {\n handler: handlerPaths.executor,\n link: [table, resource.queue, ...resource.fns],\n environment: {\n LAMBDA_FUNCTION_LIST: $jsonStringify(resource.fns.map((f) => [f.name, f.arn])),\n // needed for startJob's scheduledAt re-enqueue\n QUEUE_URL_LIST,\n },\n },\n {\n batch: {\n size: 10,\n window: '3 seconds',\n partialResponses: true,\n },\n },\n );\n }\n\n if (resource.executor === 'in-process') {\n resource.queue.subscribe(\n {\n handler: resource.handler,\n link: [table, resource.queue, ...(resource.link ?? [])],\n environment: {\n ...resource.environment,\n // in-process executors re-enqueue for scheduledAt deferrals and\n // continuations — must win over consumer-provided environment\n QUEUE_URL_LIST,\n },\n },\n {\n batch: {\n size: 10,\n window: '3 seconds',\n partialResponses: true,\n },\n },\n );\n }\n });\n}\n","import { createRequire } from 'node:module';\nimport path from 'node:path';\n\nexport interface JobsDashboardBasicAuthConfig {\n /** Plaintext username — typically wired from an SST secret. */\n username: $util.Input<string>;\n /** Plaintext password — typically wired from an SST secret. */\n password: $util.Input<string>;\n /** Realm shown in browser auth dialog. Defaults to \"Jobs Dashboard\". */\n realm?: string;\n}\n\n/**\n * The subset of the SST components namespace that {@link createJobsDashboard}\n * needs at runtime.\n *\n * Passed in rather than referenced as the `sst` global for the same reason as\n * {@link JobTableSstProvider}: this package ships as `.mjs`, and SST's config\n * evaluator skips `.mjs`/`.cjs` when injecting the `sst` global (its esbuild\n * `onLoad` plugin filters on `\\.(js|ts|jsx|tsx)$`). See the note on\n * {@link JobTableSstProvider} for the full mechanism.\n */\nexport interface JobsDashboardSstProvider {\n aws: {\n ApiGatewayV2: typeof sst.aws.ApiGatewayV2;\n StaticSite: typeof sst.aws.StaticSite;\n };\n}\n\nexport interface JobsDashboardOptions {\n /**\n * SST components namespace — pass the injected `sst` global from your\n * `sst.config.ts` (a `.ts` file, which SST *does* inject `sst` into).\n * See {@link JobsDashboardSstProvider}.\n */\n sst: JobsDashboardSstProvider;\n /**\n * Handler path for the dashboard API Lambda. The handler should call\n * `initJobs({ tableName: Resource.<JobTable>.name })` and export\n * `createJobsDashboardApiHandler()` from `@auriclabs/jobs`.\n */\n apiHandler: string;\n /** Job table — linked into the API function. */\n table: sst.aws.Dynamo;\n /** Extra linkables for the API function (beyond the table). */\n link?: unknown[];\n domain?: sst.aws.StaticSiteArgs['domain'];\n /**\n * Override the path to the `@auriclabs/jobs` package's `ui/` directory.\n * Defaults to resolving the installed package via `require.resolve`.\n */\n uiPath?: string;\n /**\n * Optional HTTP basic auth gate on the static site. When set, injects a\n * basic-auth check into the StaticSite's CloudFront viewer-request\n * function — requests without the matching `Authorization: Basic <base64>`\n * header get a 401 before any routing logic runs. Credentials are inlined\n * into the function source at deploy time via Pulumi apply.\n *\n * Note: this only gates the static UI. The API gateway URL remains\n * directly callable — browsers don't auto-send basic auth credentials\n * cross-origin, so the dashboard's fetch() can't carry them. Treat this\n * as discovery-prevention for the dashboard, not API protection.\n */\n basicAuth?: JobsDashboardBasicAuthConfig;\n}\n\nexport function createJobsDashboard(options: JobsDashboardOptions) {\n const { sst } = options;\n const api = new sst.aws.ApiGatewayV2('JobsDashboardApi', { cors: true });\n\n const link: unknown[] = [options.table, ...(options.link ?? [])];\n\n api.route('$default', {\n handler: options.apiHandler,\n link,\n });\n\n const uiPath = options.uiPath ?? resolveJobsUiPath();\n const uiRelative = path.relative(process.cwd(), uiPath);\n\n const basicAuthInjection = options.basicAuth\n ? buildBasicAuthInjection(options.basicAuth)\n : undefined;\n\n // Copy pre-built dist and inject the API URL at deploy time.\n // The build command copies ui/dist to a temp output dir and injects\n // a script tag that sets globalThis.__JOBS_API_URL__ before the app loads.\n const site = new sst.aws.StaticSite('JobsDashboard', {\n path: uiRelative,\n\n build: {\n command: [\n // _deploy persists in node_modules across deploys — a stale copy would\n // nest the new dist and keep serving the old bundle\n 'rm -rf _deploy',\n 'cp -r dist _deploy',\n `sed -i.bak 's|<head>|<head><script>globalThis.__JOBS_API_URL__=\"'$VITE_API_URL'\"</script>|' _deploy/index.html`,\n 'rm -f _deploy/index.html.bak',\n ].join(' && '),\n output: '_deploy',\n },\n dev: {\n command: 'npx vite dev',\n url: 'http://localhost:3101',\n },\n environment: {\n VITE_API_URL: api.url,\n },\n domain: options.domain,\n ...(basicAuthInjection && {\n edge: {\n viewerRequest: { injection: basicAuthInjection },\n },\n }),\n });\n\n return { api, site };\n}\n\n/**\n * Resolve the `@auriclabs/jobs` package's `ui/` directory. jobs-infra is a\n * separate package, so the UI ships with `@auriclabs/jobs` — resolve it\n * through the consumer's node_modules (the workspace link covers local dev).\n */\nfunction resolveJobsUiPath(): string {\n const require = createRequire(import.meta.url);\n const pkgJsonPath = require.resolve('@auriclabs/jobs/package.json');\n const pkgRoot = path.dirname(pkgJsonPath);\n return path.join(pkgRoot, 'ui');\n}\n\nfunction buildBasicAuthInjection(auth: JobsDashboardBasicAuthConfig) {\n const realm = (auth.realm ?? 'Jobs Dashboard').replace(/\"/g, '\\\\\"');\n\n // Inline the encoded credential into the CloudFront Function source at\n // deploy time. CFFs can't read SSM at runtime, so the credential lives\n // in the deployed function's code (same trust boundary as SST secret\n // state). Rotate by updating the upstream secret and redeploying.\n //\n // Returned as an injection string that SST splices into the start of\n // its existing `cloudfront-js-2.0` viewer-request handler — a 401\n // return short-circuits the rest of the routing logic.\n return $output([auth.username, auth.password]).apply(([username, password]) => {\n const encoded = Buffer.from(`${username}:${password}`).toString('base64');\n return [\n 'var __auth = event.request.headers.authorization && event.request.headers.authorization.value;',\n `if (__auth !== \"Basic ${encoded}\") {`,\n ' return {',\n ' statusCode: 401,',\n ' statusDescription: \"Unauthorized\",',\n ' headers: {',\n ` \"www-authenticate\": { value: 'Basic realm=\"${realm}\"' }`,\n ' }',\n ' };',\n '}',\n ].join('\\n');\n });\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@auriclabs/jobs-infra",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "SST infrastructure helpers for job queue tables and resources",
5
5
  "prettier": "@auriclabs/prettier-config",
6
6
  "main": "dist/index.cjs",
@@ -21,8 +21,8 @@
21
21
  "devDependencies": {
22
22
  "sst": "^4.3.7",
23
23
  "@auriclabs/jobs": "0.3.0",
24
- "@auriclabs/sst-utils": "1.1.14",
25
- "@auriclabs/sst-types": "0.1.0"
24
+ "@auriclabs/sst-types": "0.1.0",
25
+ "@auriclabs/sst-utils": "1.1.14"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "@auriclabs/jobs": ">=0.3.0",
package/src/dashboard.ts CHANGED
@@ -10,7 +10,30 @@ export interface JobsDashboardBasicAuthConfig {
10
10
  realm?: string;
11
11
  }
12
12
 
13
+ /**
14
+ * The subset of the SST components namespace that {@link createJobsDashboard}
15
+ * needs at runtime.
16
+ *
17
+ * Passed in rather than referenced as the `sst` global for the same reason as
18
+ * {@link JobTableSstProvider}: this package ships as `.mjs`, and SST's config
19
+ * evaluator skips `.mjs`/`.cjs` when injecting the `sst` global (its esbuild
20
+ * `onLoad` plugin filters on `\.(js|ts|jsx|tsx)$`). See the note on
21
+ * {@link JobTableSstProvider} for the full mechanism.
22
+ */
23
+ export interface JobsDashboardSstProvider {
24
+ aws: {
25
+ ApiGatewayV2: typeof sst.aws.ApiGatewayV2;
26
+ StaticSite: typeof sst.aws.StaticSite;
27
+ };
28
+ }
29
+
13
30
  export interface JobsDashboardOptions {
31
+ /**
32
+ * SST components namespace — pass the injected `sst` global from your
33
+ * `sst.config.ts` (a `.ts` file, which SST *does* inject `sst` into).
34
+ * See {@link JobsDashboardSstProvider}.
35
+ */
36
+ sst: JobsDashboardSstProvider;
14
37
  /**
15
38
  * Handler path for the dashboard API Lambda. The handler should call
16
39
  * `initJobs({ tableName: Resource.<JobTable>.name })` and export
@@ -43,6 +66,7 @@ export interface JobsDashboardOptions {
43
66
  }
44
67
 
45
68
  export function createJobsDashboard(options: JobsDashboardOptions) {
69
+ const { sst } = options;
46
70
  const api = new sst.aws.ApiGatewayV2('JobsDashboardApi', { cors: true });
47
71
 
48
72
  const link: unknown[] = [options.table, ...(options.link ?? [])];
@@ -64,6 +88,7 @@ export function createJobsDashboard(options: JobsDashboardOptions) {
64
88
  // a script tag that sets globalThis.__JOBS_API_URL__ before the app loads.
65
89
  const site = new sst.aws.StaticSite('JobsDashboard', {
66
90
  path: uiRelative,
91
+
67
92
  build: {
68
93
  command: [
69
94
  // _deploy persists in node_modules across deploys — a stale copy would
package/src/job-table.ts CHANGED
@@ -1,4 +1,25 @@
1
- export function createJobTable(name: string) {
1
+ /**
2
+ * The subset of the SST components namespace that {@link createJobTable} needs
3
+ * at runtime.
4
+ *
5
+ * `@auriclabs/jobs-infra` ships as ESM (`dist/index.mjs`). SST's config
6
+ * evaluator injects the `sst` global into config source via an esbuild
7
+ * `onLoad` plugin whose filter is `\.(js|ts|jsx|tsx)$` — it deliberately skips
8
+ * `.mjs`/`.cjs`. (The `$app` / `$jsonStringify` / `$output` globals arrive via
9
+ * esbuild `Define`/`Inject`, which are extension-agnostic, so those keep
10
+ * working; only the `sst` namespace and the `@pulumi/*` provider aliases come
11
+ * from the skipped `onLoad` channel.) A bare `sst.aws.Dynamo` reference in this
12
+ * `.mjs` file therefore throws `ReferenceError: sst is not defined` at deploy
13
+ * time. Taking `sst` as a parameter — exactly as `@auriclabs/migrations`'
14
+ * `createTable(sst)` does — sidesteps the injection entirely.
15
+ */
16
+ export interface JobTableSstProvider {
17
+ aws: {
18
+ Dynamo: typeof sst.aws.Dynamo;
19
+ };
20
+ }
21
+
22
+ export function createJobTable(sst: JobTableSstProvider, name: string) {
2
23
  return new sst.aws.Dynamo(name, {
3
24
  fields: {
4
25
  pk: 'string',