@knpkv/hub-app 0.0.0-stage → 0.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.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +54 -2
  3. package/dist/client.d.ts +67 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +17 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/hub-client.d.ts +52 -0
  8. package/dist/hub-client.d.ts.map +1 -0
  9. package/dist/hub-client.js +97 -0
  10. package/dist/hub-client.js.map +1 -0
  11. package/dist/index.d.ts +6 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +6 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/main.d.ts +4 -0
  16. package/dist/main.d.ts.map +1 -0
  17. package/dist/main.js +29 -0
  18. package/dist/main.js.map +1 -0
  19. package/dist/manifest.d.ts +267 -0
  20. package/dist/manifest.d.ts.map +1 -0
  21. package/dist/manifest.js +107 -0
  22. package/dist/manifest.js.map +1 -0
  23. package/dist/module.d.ts +38 -0
  24. package/dist/module.d.ts.map +1 -0
  25. package/dist/module.js +70 -0
  26. package/dist/module.js.map +1 -0
  27. package/dist/node.d.ts +50 -0
  28. package/dist/node.d.ts.map +1 -0
  29. package/dist/node.js +253 -0
  30. package/dist/node.js.map +1 -0
  31. package/dist/route.d.ts +91 -0
  32. package/dist/route.d.ts.map +1 -0
  33. package/dist/route.js +88 -0
  34. package/dist/route.js.map +1 -0
  35. package/dist/standalone-page.d.ts +3 -0
  36. package/dist/standalone-page.d.ts.map +1 -0
  37. package/dist/standalone-page.js +28 -0
  38. package/dist/standalone-page.js.map +1 -0
  39. package/dist/standalone-shell.js +27 -0
  40. package/dist/standalone.d.ts +17 -0
  41. package/dist/standalone.d.ts.map +1 -0
  42. package/dist/standalone.js +140 -0
  43. package/dist/standalone.js.map +1 -0
  44. package/dist/wire.d.ts +75 -0
  45. package/dist/wire.d.ts.map +1 -0
  46. package/dist/wire.js +67 -0
  47. package/dist/wire.js.map +1 -0
  48. package/package.json +62 -3
@@ -0,0 +1,267 @@
1
+ /**
2
+ * What an app says about itself, what nix tells the hub, and what the hub concludes per app.
3
+ *
4
+ * **Mental model**
5
+ *
6
+ * - `apps.json` (written by nix) holds only ids and sockets. Everything else comes from the app's own
7
+ * `GET /app/manifest`, so the file can't disagree with the code.
8
+ * - `contract` is one integer for the whole shell ↔ app surface: manifest shape, wire paths, shell
9
+ * services and `ShellContext`. Additive changes keep it; the hub supports the current and previous one.
10
+ * - Every per-app problem becomes an {@link AppState} `Unavailable`, never a hub failure.
11
+ *
12
+ * @module
13
+ */
14
+ import { Schema } from "effect";
15
+ /** Contracts this package's runner and types speak. The hub declares its own supported list. */
16
+ export declare const AppContract: Schema.Literals<readonly [1]>;
17
+ export type AppContract = typeof AppContract.Type;
18
+ export declare const AppId: Schema.brand<Schema.String, "AppId">;
19
+ export type AppId = typeof AppId.Type;
20
+ /** Hub services an app may call; an undeclared one fails with `ShellServiceUnavailable("undeclared")`. */
21
+ export declare const ShellService: Schema.Literals<readonly ["fleet.read", "host", "jobs.submit", "relay.post", "needs-you", "badge"]>;
22
+ export type ShellService = typeof ShellService.Type;
23
+ /** The client the runner serves under `/app/assets/`: one ES module entry and its stylesheets. */
24
+ export declare const AppClientAssets: Schema.Struct<{
25
+ readonly entry: Schema.String;
26
+ readonly css: Schema.$Array<Schema.String>;
27
+ }>;
28
+ export type AppClientAssets = typeof AppClientAssets.Type;
29
+ /** Served at `GET /app/manifest`. `module.id` is the app id; the version is display-only. */
30
+ export declare const AppManifest: Schema.Struct<{
31
+ readonly contract: Schema.Int;
32
+ readonly id: Schema.brand<Schema.String, "AppId">;
33
+ readonly package: Schema.String;
34
+ readonly version: Schema.String;
35
+ readonly module: Schema.Struct<{
36
+ readonly id: Schema.String;
37
+ readonly label: Schema.String;
38
+ readonly defaultPage: Schema.String;
39
+ readonly pages: Schema.$Array<Schema.Struct<{
40
+ readonly id: Schema.String;
41
+ readonly label: Schema.String;
42
+ readonly showInPhoneTitle: Schema.optionalKey<Schema.Boolean>;
43
+ }>>;
44
+ readonly listeners: Schema.$Array<Schema.Literals<readonly ["serve", "local", "approval", "tailnet", "lan"]>>;
45
+ readonly requires: Schema.$Array<Schema.Literals<readonly ["read", "write"]>>;
46
+ }>;
47
+ readonly client: Schema.Struct<{
48
+ readonly entry: Schema.String;
49
+ readonly css: Schema.$Array<Schema.String>;
50
+ }>;
51
+ readonly services: Schema.$Array<Schema.Literals<readonly ["fleet.read", "host", "jobs.submit", "relay.post", "needs-you", "badge"]>>;
52
+ readonly nav: Schema.Struct<{
53
+ readonly order: Schema.Int;
54
+ readonly primary: Schema.Boolean;
55
+ readonly mobile: Schema.Boolean;
56
+ }>;
57
+ readonly standalone: Schema.Struct<{
58
+ readonly defaultPort: Schema.Int;
59
+ }>;
60
+ }>;
61
+ export interface AppManifest extends Schema.Schema.Type<typeof AppManifest> {
62
+ }
63
+ /** What an app declares in code; the runner adds `client` from its build output. */
64
+ export type AppManifestInput = Omit<AppManifest, "client">;
65
+ /** `~/.config/herdr/apps.json`, written by nix. Unknown keys are refused. */
66
+ export declare const AppsConfig: Schema.Struct<{
67
+ readonly v: Schema.Literal<1>;
68
+ readonly apps: Schema.$Array<Schema.Struct<{
69
+ readonly id: Schema.brand<Schema.String, "AppId">;
70
+ readonly socket: Schema.String;
71
+ }>>;
72
+ }>;
73
+ export interface AppsConfig extends Schema.Schema.Type<typeof AppsConfig> {
74
+ }
75
+ export declare const AppUnavailableReason: Schema.Literals<readonly ["not_running", "timeout", "invalid_manifest", "id_mismatch", "incompatible", "duplicate", "client_failed"]>;
76
+ export type AppUnavailableReason = typeof AppUnavailableReason.Type;
77
+ /**
78
+ * The hub's view of one registered app, served by `GET /v1/apps`. `Unavailable` keeps the last good
79
+ * manifest, when there is one, so the shell still shows the app's real label and pages.
80
+ */
81
+ export declare const AppState: Schema.Union<readonly [Schema.TaggedStruct<"Ready", {
82
+ readonly manifest: Schema.Struct<{
83
+ readonly contract: Schema.Int;
84
+ readonly id: Schema.brand<Schema.String, "AppId">;
85
+ readonly package: Schema.String;
86
+ readonly version: Schema.String;
87
+ readonly module: Schema.Struct<{
88
+ readonly id: Schema.String;
89
+ readonly label: Schema.String;
90
+ readonly defaultPage: Schema.String;
91
+ readonly pages: Schema.$Array<Schema.Struct<{
92
+ readonly id: Schema.String;
93
+ readonly label: Schema.String;
94
+ readonly showInPhoneTitle: Schema.optionalKey<Schema.Boolean>;
95
+ }>>;
96
+ readonly listeners: Schema.$Array<Schema.Literals<readonly ["serve", "local", "approval", "tailnet", "lan"]>>;
97
+ readonly requires: Schema.$Array<Schema.Literals<readonly ["read", "write"]>>;
98
+ }>;
99
+ readonly client: Schema.Struct<{
100
+ readonly entry: Schema.String;
101
+ readonly css: Schema.$Array<Schema.String>;
102
+ }>;
103
+ readonly services: Schema.$Array<Schema.Literals<readonly ["fleet.read", "host", "jobs.submit", "relay.post", "needs-you", "badge"]>>;
104
+ readonly nav: Schema.Struct<{
105
+ readonly order: Schema.Int;
106
+ readonly primary: Schema.Boolean;
107
+ readonly mobile: Schema.Boolean;
108
+ }>;
109
+ readonly standalone: Schema.Struct<{
110
+ readonly defaultPort: Schema.Int;
111
+ }>;
112
+ }>;
113
+ }>, Schema.TaggedStruct<"Unavailable", {
114
+ readonly id: Schema.brand<Schema.String, "AppId">;
115
+ readonly manifest: Schema.NullOr<Schema.Struct<{
116
+ readonly contract: Schema.Int;
117
+ readonly id: Schema.brand<Schema.String, "AppId">;
118
+ readonly package: Schema.String;
119
+ readonly version: Schema.String;
120
+ readonly module: Schema.Struct<{
121
+ readonly id: Schema.String;
122
+ readonly label: Schema.String;
123
+ readonly defaultPage: Schema.String;
124
+ readonly pages: Schema.$Array<Schema.Struct<{
125
+ readonly id: Schema.String;
126
+ readonly label: Schema.String;
127
+ readonly showInPhoneTitle: Schema.optionalKey<Schema.Boolean>;
128
+ }>>;
129
+ readonly listeners: Schema.$Array<Schema.Literals<readonly ["serve", "local", "approval", "tailnet", "lan"]>>;
130
+ readonly requires: Schema.$Array<Schema.Literals<readonly ["read", "write"]>>;
131
+ }>;
132
+ readonly client: Schema.Struct<{
133
+ readonly entry: Schema.String;
134
+ readonly css: Schema.$Array<Schema.String>;
135
+ }>;
136
+ readonly services: Schema.$Array<Schema.Literals<readonly ["fleet.read", "host", "jobs.submit", "relay.post", "needs-you", "badge"]>>;
137
+ readonly nav: Schema.Struct<{
138
+ readonly order: Schema.Int;
139
+ readonly primary: Schema.Boolean;
140
+ readonly mobile: Schema.Boolean;
141
+ }>;
142
+ readonly standalone: Schema.Struct<{
143
+ readonly defaultPort: Schema.Int;
144
+ }>;
145
+ }>>;
146
+ readonly reason: Schema.Literals<readonly ["not_running", "timeout", "invalid_manifest", "id_mismatch", "incompatible", "duplicate", "client_failed"]>;
147
+ readonly detail: Schema.String;
148
+ }>]>;
149
+ export type AppState = typeof AppState.Type;
150
+ export declare const AppStates: Schema.Struct<{
151
+ readonly contract: Schema.Literals<readonly [1]>;
152
+ readonly apps: Schema.$Array<Schema.Union<readonly [Schema.TaggedStruct<"Ready", {
153
+ readonly manifest: Schema.Struct<{
154
+ readonly contract: Schema.Int;
155
+ readonly id: Schema.brand<Schema.String, "AppId">;
156
+ readonly package: Schema.String;
157
+ readonly version: Schema.String;
158
+ readonly module: Schema.Struct<{
159
+ readonly id: Schema.String;
160
+ readonly label: Schema.String;
161
+ readonly defaultPage: Schema.String;
162
+ readonly pages: Schema.$Array<Schema.Struct<{
163
+ readonly id: Schema.String;
164
+ readonly label: Schema.String;
165
+ readonly showInPhoneTitle: Schema.optionalKey<Schema.Boolean>;
166
+ }>>;
167
+ readonly listeners: Schema.$Array<Schema.Literals<readonly ["serve", "local", "approval", "tailnet", "lan"]>>;
168
+ readonly requires: Schema.$Array<Schema.Literals<readonly ["read", "write"]>>;
169
+ }>;
170
+ readonly client: Schema.Struct<{
171
+ readonly entry: Schema.String;
172
+ readonly css: Schema.$Array<Schema.String>;
173
+ }>;
174
+ readonly services: Schema.$Array<Schema.Literals<readonly ["fleet.read", "host", "jobs.submit", "relay.post", "needs-you", "badge"]>>;
175
+ readonly nav: Schema.Struct<{
176
+ readonly order: Schema.Int;
177
+ readonly primary: Schema.Boolean;
178
+ readonly mobile: Schema.Boolean;
179
+ }>;
180
+ readonly standalone: Schema.Struct<{
181
+ readonly defaultPort: Schema.Int;
182
+ }>;
183
+ }>;
184
+ }>, Schema.TaggedStruct<"Unavailable", {
185
+ readonly id: Schema.brand<Schema.String, "AppId">;
186
+ readonly manifest: Schema.NullOr<Schema.Struct<{
187
+ readonly contract: Schema.Int;
188
+ readonly id: Schema.brand<Schema.String, "AppId">;
189
+ readonly package: Schema.String;
190
+ readonly version: Schema.String;
191
+ readonly module: Schema.Struct<{
192
+ readonly id: Schema.String;
193
+ readonly label: Schema.String;
194
+ readonly defaultPage: Schema.String;
195
+ readonly pages: Schema.$Array<Schema.Struct<{
196
+ readonly id: Schema.String;
197
+ readonly label: Schema.String;
198
+ readonly showInPhoneTitle: Schema.optionalKey<Schema.Boolean>;
199
+ }>>;
200
+ readonly listeners: Schema.$Array<Schema.Literals<readonly ["serve", "local", "approval", "tailnet", "lan"]>>;
201
+ readonly requires: Schema.$Array<Schema.Literals<readonly ["read", "write"]>>;
202
+ }>;
203
+ readonly client: Schema.Struct<{
204
+ readonly entry: Schema.String;
205
+ readonly css: Schema.$Array<Schema.String>;
206
+ }>;
207
+ readonly services: Schema.$Array<Schema.Literals<readonly ["fleet.read", "host", "jobs.submit", "relay.post", "needs-you", "badge"]>>;
208
+ readonly nav: Schema.Struct<{
209
+ readonly order: Schema.Int;
210
+ readonly primary: Schema.Boolean;
211
+ readonly mobile: Schema.Boolean;
212
+ }>;
213
+ readonly standalone: Schema.Struct<{
214
+ readonly defaultPort: Schema.Int;
215
+ }>;
216
+ }>>;
217
+ readonly reason: Schema.Literals<readonly ["not_running", "timeout", "invalid_manifest", "id_mismatch", "incompatible", "duplicate", "client_failed"]>;
218
+ readonly detail: Schema.String;
219
+ }>]>>;
220
+ }>;
221
+ export interface AppStates extends Schema.Schema.Type<typeof AppStates> {
222
+ }
223
+ declare const AppsConfigInvalid_base: Schema.Class<AppsConfigInvalid, Schema.TaggedStruct<"AppsConfigInvalid", {
224
+ readonly path: Schema.String;
225
+ }>, import("effect/Cause").YieldableError>;
226
+ /** `apps.json` exists but doesn't decode; the hub keeps its previous app list. */
227
+ export declare class AppsConfigInvalid extends AppsConfigInvalid_base {
228
+ }
229
+ declare const AppProbeFailed_base: Schema.Class<AppProbeFailed, Schema.TaggedStruct<"AppProbeFailed", {
230
+ readonly id: Schema.brand<Schema.String, "AppId">;
231
+ readonly reason: Schema.Literals<readonly ["not_running", "timeout", "invalid_manifest", "id_mismatch", "incompatible", "duplicate", "client_failed"]>;
232
+ readonly detail: Schema.String;
233
+ }>, import("effect/Cause").YieldableError>;
234
+ /** One probe's outcome other than `Ready`. */
235
+ export declare class AppProbeFailed extends AppProbeFailed_base {
236
+ }
237
+ declare const AppUnavailable_base: Schema.Class<AppUnavailable, Schema.TaggedStruct<"AppUnavailable", {
238
+ readonly id: Schema.brand<Schema.String, "AppId">;
239
+ }>, import("effect/Cause").YieldableError>;
240
+ /** A proxied request reached an app that isn't answering. The proxy answers 503 `app_unavailable`. */
241
+ export declare class AppUnavailable extends AppUnavailable_base {
242
+ }
243
+ declare const GrantInvalid_base: Schema.Class<GrantInvalid, Schema.TaggedStruct<"GrantInvalid", {
244
+ readonly reason: Schema.Literals<readonly ["unknown", "expired", "used", "app_mismatch", "read_only"]>;
245
+ }>, import("effect/Cause").YieldableError>;
246
+ /**
247
+ * A grant the hub doesn't recognise, has expired, was already spent, belongs to another app, or was minted for a
248
+ * read (`read_only`: a GET skips the same-origin check, so its grant may not submit a job).
249
+ */
250
+ export declare class GrantInvalid extends GrantInvalid_base {
251
+ }
252
+ declare const ShellServiceUnavailable_base: Schema.Class<ShellServiceUnavailable, Schema.TaggedStruct<"ShellServiceUnavailable", {
253
+ readonly service: Schema.Literals<readonly ["fleet.read", "host", "jobs.submit", "relay.post", "needs-you", "badge"]>;
254
+ readonly reason: Schema.Literals<readonly ["standalone", "undeclared", "hub_down"]>;
255
+ }>, import("effect/Cause").YieldableError>;
256
+ /** A shell service the app can't use here: running standalone, not declared, or the hub is down. */
257
+ export declare class ShellServiceUnavailable extends ShellServiceUnavailable_base {
258
+ }
259
+ declare const AppStartError_base: Schema.Class<AppStartError, Schema.TaggedStruct<"AppStartError", {
260
+ readonly reason: Schema.Literals<readonly ["invalid_manifest", "invalid_arguments", "listen", "layer"]>;
261
+ readonly cause: Schema.Defect;
262
+ }>, import("effect/Cause").YieldableError>;
263
+ /** The app couldn't start: its manifest, its listener, or its handler layer. */
264
+ export declare class AppStartError extends AppStartError_base {
265
+ }
266
+ export {};
267
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAG/B,gGAAgG;AAChG,eAAO,MAAM,WAAW,+BAAuB,CAAA;AAC/C,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,IAAI,CAAA;AAEjD,eAAO,MAAM,KAAK,sCAEjB,CAAA;AACD,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,IAAI,CAAA;AAErC,0GAA0G;AAC1G,eAAO,MAAM,YAAY,qGAA6F,CAAA;AACtH,MAAM,MAAM,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AAInD,kGAAkG;AAClG,eAAO,MAAM,eAAe;;;EAG1B,CAAA;AACF,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,CAAC,IAAI,CAAA;AAEzD,6FAA6F;AAC7F,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EActB,CAAA;AACF,MAAM,WAAW,WAAY,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,WAAW,CAAC;CAAG;AAE9E,oFAAoF;AACpF,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;AAI1D,6EAA6E;AAC7E,eAAO,MAAM,UAAU;;;;;;EAGrB,CAAA;AACF,MAAM,WAAW,UAAW,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,UAAU,CAAC;CAAG;AAE5E,eAAO,MAAM,oBAAoB,uIAQ/B,CAAA;AACF,MAAM,MAAM,oBAAoB,GAAG,OAAO,oBAAoB,CAAC,IAAI,CAAA;AAEnE;;;GAGG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAQnB,CAAA;AACF,MAAM,MAAM,QAAQ,GAAG,OAAO,QAAQ,CAAC,IAAI,CAAA;AAE3C,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAyE,CAAA;AAC/F,MAAM,WAAW,SAAU,SAAQ,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,SAAS,CAAC;CAAG;;;;AAE1E,kFAAkF;AAClF,qBAAa,iBAAkB,SAAQ,sBAErC;CAAG;;;;;;AAEL,8CAA8C;AAC9C,qBAAa,cAAe,SAAQ,mBAIlC;CAAG;;;;AAEL,sGAAsG;AACtG,qBAAa,cAAe,SAAQ,mBAAqE;CAAG;;;;AAE5G;;;GAGG;AACH,qBAAa,YAAa,SAAQ,iBAEhC;CAAG;;;;;AAEL,oGAAoG;AACpG,qBAAa,uBAAwB,SAAQ,4BAM5C;CAAG;;;;;AAEJ,gFAAgF;AAChF,qBAAa,aAAc,SAAQ,kBAGjC;CAAG"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * What an app says about itself, what nix tells the hub, and what the hub concludes per app.
3
+ *
4
+ * **Mental model**
5
+ *
6
+ * - `apps.json` (written by nix) holds only ids and sockets. Everything else comes from the app's own
7
+ * `GET /app/manifest`, so the file can't disagree with the code.
8
+ * - `contract` is one integer for the whole shell ↔ app surface: manifest shape, wire paths, shell
9
+ * services and `ShellContext`. Additive changes keep it; the hub supports the current and previous one.
10
+ * - Every per-app problem becomes an {@link AppState} `Unavailable`, never a hub failure.
11
+ *
12
+ * @module
13
+ */
14
+ import { Schema } from "effect";
15
+ import { ModuleDescriptor } from "./module.js";
16
+ /** Contracts this package's runner and types speak. The hub declares its own supported list. */
17
+ export const AppContract = Schema.Literals([1]);
18
+ export const AppId = Schema.String.check(Schema.isPattern(/^[a-z][a-z0-9-]*$/), Schema.isMaxLength(64)).pipe(Schema.brand("AppId"));
19
+ /** Hub services an app may call; an undeclared one fails with `ShellServiceUnavailable("undeclared")`. */
20
+ export const ShellService = Schema.Literals(["fleet.read", "host", "jobs.submit", "relay.post", "needs-you", "badge"]);
21
+ const AssetPath = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9._-]+(\/[A-Za-z0-9._-]+)*$/));
22
+ /** The client the runner serves under `/app/assets/`: one ES module entry and its stylesheets. */
23
+ export const AppClientAssets = Schema.Struct({
24
+ entry: AssetPath,
25
+ css: Schema.Array(AssetPath)
26
+ });
27
+ /** Served at `GET /app/manifest`. `module.id` is the app id; the version is display-only. */
28
+ export const AppManifest = Schema.Struct({
29
+ contract: Schema.Int.check(Schema.isGreaterThanOrEqualTo(1)),
30
+ id: AppId,
31
+ package: Schema.String.check(Schema.isNonEmpty(), Schema.isMaxLength(214)),
32
+ version: Schema.String.check(Schema.isNonEmpty(), Schema.isMaxLength(64)),
33
+ module: ModuleDescriptor,
34
+ client: AppClientAssets,
35
+ services: Schema.Array(ShellService),
36
+ nav: Schema.Struct({
37
+ order: Schema.Int,
38
+ primary: Schema.Boolean,
39
+ mobile: Schema.Boolean
40
+ }),
41
+ standalone: Schema.Struct({ defaultPort: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 65_535 })) })
42
+ });
43
+ const SocketPath = Schema.String.check(Schema.isPattern(/^\//), Schema.isMaxLength(107));
44
+ /** `~/.config/herdr/apps.json`, written by nix. Unknown keys are refused. */
45
+ export const AppsConfig = Schema.Struct({
46
+ v: Schema.Literal(1),
47
+ apps: Schema.Array(Schema.Struct({ id: AppId, socket: SocketPath }))
48
+ });
49
+ export const AppUnavailableReason = Schema.Literals([
50
+ "not_running",
51
+ "timeout",
52
+ "invalid_manifest",
53
+ "id_mismatch",
54
+ "incompatible",
55
+ "duplicate",
56
+ "client_failed"
57
+ ]);
58
+ /**
59
+ * The hub's view of one registered app, served by `GET /v1/apps`. `Unavailable` keeps the last good
60
+ * manifest, when there is one, so the shell still shows the app's real label and pages.
61
+ */
62
+ export const AppState = Schema.Union([
63
+ Schema.TaggedStruct("Ready", { manifest: AppManifest }),
64
+ Schema.TaggedStruct("Unavailable", {
65
+ id: AppId,
66
+ manifest: Schema.NullOr(AppManifest),
67
+ reason: AppUnavailableReason,
68
+ detail: Schema.String
69
+ })
70
+ ]);
71
+ export const AppStates = Schema.Struct({ contract: AppContract, apps: Schema.Array(AppState) });
72
+ /** `apps.json` exists but doesn't decode; the hub keeps its previous app list. */
73
+ export class AppsConfigInvalid extends Schema.TaggedError()("AppsConfigInvalid", {
74
+ path: Schema.String
75
+ }) {
76
+ }
77
+ /** One probe's outcome other than `Ready`. */
78
+ export class AppProbeFailed extends Schema.TaggedError()("AppProbeFailed", {
79
+ id: AppId,
80
+ reason: AppUnavailableReason,
81
+ detail: Schema.String
82
+ }) {
83
+ }
84
+ /** A proxied request reached an app that isn't answering. The proxy answers 503 `app_unavailable`. */
85
+ export class AppUnavailable extends Schema.TaggedError()("AppUnavailable", { id: AppId }) {
86
+ }
87
+ /**
88
+ * A grant the hub doesn't recognise, has expired, was already spent, belongs to another app, or was minted for a
89
+ * read (`read_only`: a GET skips the same-origin check, so its grant may not submit a job).
90
+ */
91
+ export class GrantInvalid extends Schema.TaggedError()("GrantInvalid", {
92
+ reason: Schema.Literals(["unknown", "expired", "used", "app_mismatch", "read_only"])
93
+ }) {
94
+ }
95
+ /** A shell service the app can't use here: running standalone, not declared, or the hub is down. */
96
+ export class ShellServiceUnavailable extends Schema.TaggedError()("ShellServiceUnavailable", {
97
+ service: ShellService,
98
+ reason: Schema.Literals(["standalone", "undeclared", "hub_down"])
99
+ }) {
100
+ }
101
+ /** The app couldn't start: its manifest, its listener, or its handler layer. */
102
+ export class AppStartError extends Schema.TaggedError()("AppStartError", {
103
+ reason: Schema.Literals(["invalid_manifest", "invalid_arguments", "listen", "layer"]),
104
+ cause: Schema.Defect()
105
+ }) {
106
+ }
107
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /** Module metadata shared by the hub shell, its core modules and every app. Moved from herdr-hub. @module */
2
+ import { Result, Schema } from "effect";
3
+ export declare const ModuleListener: Schema.Literals<readonly ["serve", "local", "approval", "tailnet", "lan"]>;
4
+ export type ModuleListener = typeof ModuleListener.Type;
5
+ /** Shared metadata. `requires` describes UI capabilities; the server mount enforces access. */
6
+ export declare const ModuleDescriptor: Schema.Struct<{
7
+ readonly id: Schema.String;
8
+ readonly label: Schema.String;
9
+ readonly defaultPage: Schema.String;
10
+ readonly pages: Schema.$Array<Schema.Struct<{
11
+ readonly id: Schema.String;
12
+ readonly label: Schema.String;
13
+ /** @deprecated Ignored: the phone header shows the product name and the breadcrumb names the page. */
14
+ readonly showInPhoneTitle: Schema.optionalKey<Schema.Boolean>;
15
+ }>>;
16
+ readonly listeners: Schema.$Array<Schema.Literals<readonly ["serve", "local", "approval", "tailnet", "lan"]>>;
17
+ readonly requires: Schema.$Array<Schema.Literals<readonly ["read", "write"]>>;
18
+ }>;
19
+ export type ModuleDescriptor = typeof ModuleDescriptor.Type;
20
+ declare const ModuleRegistrationError_base: Schema.Class<ModuleRegistrationError, Schema.TaggedStruct<"ModuleRegistrationError", {
21
+ readonly module: Schema.String;
22
+ readonly reason: Schema.Literals<readonly ["invalid_descriptor", "duplicate_module", "duplicate_page", "missing_default", "server_mismatch", "browser_mismatch", "invalid_route", "duplicate_route"]>;
23
+ }>, import("effect/Cause").YieldableError>;
24
+ export declare class ModuleRegistrationError extends ModuleRegistrationError_base {
25
+ }
26
+ /** Reject ambiguous namespaces and missing pages before a browser or server registry is used. */
27
+ export declare const validateModuleRegistry: (input: ReadonlyArray<ModuleDescriptor>) => Result.Result<ReadonlyArray<ModuleDescriptor>, ModuleRegistrationError>;
28
+ /** Retains literal page identities. Registration validates this metadata before mounting it. */
29
+ export declare const defineModule: <const D extends ModuleDescriptor>(descriptor: D) => D;
30
+ /** Each page belongs to its descriptor; query parameters select objects inside the owning page. */
31
+ export type ModuleDestination<D extends ModuleDescriptor = ModuleDescriptor> = D extends ModuleDescriptor ? {
32
+ readonly module: D["id"];
33
+ readonly page: D["pages"][number]["id"];
34
+ } : never;
35
+ /** Compare complete registrations across separate bundles without relying on object identity. */
36
+ export declare const moduleRegistryFingerprint: (descriptors: ReadonlyArray<ModuleDescriptor>) => string;
37
+ export {};
38
+ //# sourceMappingURL=module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,6GAA6G;AAC7G,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAKvC,eAAO,MAAM,cAAc,4EAAoE,CAAA;AAC/F,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAA;AAEvD,+FAA+F;AAC/F,eAAO,MAAM,gBAAgB;;;;;;;QAOzB,sGAAsG;;;;;EAKxG,CAAA;AACF,MAAM,MAAM,gBAAgB,GAAG,OAAO,gBAAgB,CAAC,IAAI,CAAA;;;;;AAE3D,qBAAa,uBAAwB,SAAQ,4BAY3C;CAAG;AAEL,iGAAiG;AACjG,eAAO,MAAM,sBAAsB,UAC1B,aAAa,CAAC,gBAAgB,CAAC,KACrC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,EAAE,uBAAuB,CAuBxE,CAAA;AAED,gGAAgG;AAChG,eAAO,MAAM,YAAY,GAAI,KAAK,CAAC,CAAC,SAAS,gBAAgB,cAAc,CAAC,KAAG,CAAe,CAAA;AAE9F,mGAAmG;AACnG,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,gBAAgB,GAAG,gBAAgB,IAAI,CAAC,SAAS,gBAAgB,GACrG;IAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAA;CAAE,GACrE,KAAK,CAAA;AAET,iGAAiG;AACjG,eAAO,MAAM,yBAAyB,gBAAiB,aAAa,CAAC,gBAAgB,CAAC,KAAG,MAUtF,CAAA"}
package/dist/module.js ADDED
@@ -0,0 +1,70 @@
1
+ /** Module metadata shared by the hub shell, its core modules and every app. Moved from herdr-hub. @module */
2
+ import { Result, Schema } from "effect";
3
+ const Segment = Schema.String.check(Schema.isPattern(/^[a-z][a-z0-9-]*$/));
4
+ const Label = Schema.String.check(Schema.isMinLength(1));
5
+ export const ModuleListener = Schema.Literals(["serve", "local", "approval", "tailnet", "lan"]);
6
+ /** Shared metadata. `requires` describes UI capabilities; the server mount enforces access. */
7
+ export const ModuleDescriptor = Schema.Struct({
8
+ id: Segment,
9
+ label: Label,
10
+ defaultPage: Segment,
11
+ pages: Schema.Array(Schema.Struct({
12
+ id: Segment,
13
+ label: Label,
14
+ /** @deprecated Ignored: the phone header shows the product name and the breadcrumb names the page. */
15
+ showInPhoneTitle: Schema.optionalKey(Schema.Boolean)
16
+ })).check(Schema.isMinLength(1)),
17
+ listeners: Schema.Array(ModuleListener).check(Schema.isMinLength(1)),
18
+ requires: Schema.Array(Schema.Literals(["read", "write"]))
19
+ });
20
+ export class ModuleRegistrationError extends Schema.TaggedError()("ModuleRegistrationError", {
21
+ module: Schema.String,
22
+ reason: Schema.Literals([
23
+ "invalid_descriptor",
24
+ "duplicate_module",
25
+ "duplicate_page",
26
+ "missing_default",
27
+ "server_mismatch",
28
+ "browser_mismatch",
29
+ "invalid_route",
30
+ "duplicate_route"
31
+ ])
32
+ }) {
33
+ }
34
+ /** Reject ambiguous namespaces and missing pages before a browser or server registry is used. */
35
+ export const validateModuleRegistry = (input) => {
36
+ const decoded = Schema.decodeUnknownResult(Schema.Array(ModuleDescriptor))(input);
37
+ if (Result.isFailure(decoded)) {
38
+ return Result.fail(new ModuleRegistrationError({ module: "registry", reason: "invalid_descriptor" }));
39
+ }
40
+ const modules = new Set();
41
+ for (const descriptor of decoded.success) {
42
+ if (modules.has(descriptor.id)) {
43
+ return Result.fail(new ModuleRegistrationError({ module: descriptor.id, reason: "duplicate_module" }));
44
+ }
45
+ modules.add(descriptor.id);
46
+ const pages = new Set();
47
+ for (const page of descriptor.pages) {
48
+ if (pages.has(page.id)) {
49
+ return Result.fail(new ModuleRegistrationError({ module: descriptor.id, reason: "duplicate_page" }));
50
+ }
51
+ pages.add(page.id);
52
+ }
53
+ if (!pages.has(descriptor.defaultPage)) {
54
+ return Result.fail(new ModuleRegistrationError({ module: descriptor.id, reason: "missing_default" }));
55
+ }
56
+ }
57
+ return Result.succeed(decoded.success);
58
+ };
59
+ /** Retains literal page identities. Registration validates this metadata before mounting it. */
60
+ export const defineModule = (descriptor) => descriptor;
61
+ /** Compare complete registrations across separate bundles without relying on object identity. */
62
+ export const moduleRegistryFingerprint = (descriptors) => Schema.encodeSync(Schema.fromJsonString(Schema.Array(ModuleDescriptor)))(descriptors
63
+ .map((descriptor) => ({
64
+ ...descriptor,
65
+ pages: [...descriptor.pages].sort((a, b) => a.id.localeCompare(b.id)),
66
+ listeners: [...descriptor.listeners].sort(),
67
+ requires: [...descriptor.requires].sort()
68
+ }))
69
+ .sort((a, b) => a.id.localeCompare(b.id)));
70
+ //# sourceMappingURL=module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"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"}
package/dist/node.d.ts ADDED
@@ -0,0 +1,50 @@
1
+ import type { BrowserLaunch } from "@knpkv/browser-pairing/launch";
2
+ import { Effect, FileSystem, Layer, Path, Result, Schema } from "effect";
3
+ import type { ShellServices } from "./hub-client.js";
4
+ import { type AppManifestInput, AppStartError } from "./manifest.js";
5
+ import { ModuleHandlers } from "./route.js";
6
+ /** What an app hands the runner. Handlers may use {@link ShellServices}; the runner provides it. */
7
+ export interface AppServer<E, R> {
8
+ readonly manifest: AppManifestInput;
9
+ readonly handlers: Layer.Layer<ModuleHandlers, E, R | ShellServices>;
10
+ readonly badge?: Effect.Effect<{
11
+ readonly text: string;
12
+ readonly label: string;
13
+ } | null, never, ShellServices>;
14
+ /** The built client: a directory holding `client.js` and, optionally, `client.css`. */
15
+ readonly clientDirectory: string;
16
+ }
17
+ export declare const RunMode: Schema.Union<readonly [Schema.TaggedStruct<"Attached", {
18
+ readonly socket: Schema.String;
19
+ readonly hubUrl: Schema.String;
20
+ readonly tokenFile: Schema.String;
21
+ }>, Schema.TaggedStruct<"Standalone", {
22
+ readonly port: Schema.Int;
23
+ readonly open: Schema.Boolean;
24
+ }>]>;
25
+ export type RunMode = typeof RunMode.Type;
26
+ /** Read the mode from argv and environment. `--socket` means attached; anything else is standalone. */
27
+ export declare const readRunMode: (manifest: AppManifestInput, argv: ReadonlyArray<string>, env: Readonly<Record<string, string | undefined>>) => Result.Result<RunMode, AppStartError>;
28
+ /** Attached mode alone: what the hub and its tests run. Needs no browser opener. */
29
+ export declare const serveAttached: <E, R>(app: AppServer<E, R>, mode: {
30
+ readonly _tag: "Attached";
31
+ readonly socket: string;
32
+ readonly hubUrl: string;
33
+ readonly tokenFile: string;
34
+ }) => Effect.Effect<never, AppStartError | import("effect/PlatformError").PlatformError | import("effect/http/HttpServerError").ServeError, FileSystem.FileSystem | import("effect/http/HttpClient").HttpClient | Path.Path | import("effect/Scope").Scope | Exclude<R, ShellServices>>;
35
+ /**
36
+ * Serve the app in `mode` until interrupted. `launch` says whether standalone mode opens a browser for its
37
+ * sign-in link; the executable decides it from its terminal and environment.
38
+ */
39
+ export declare const serveApp: <E, R>(app: AppServer<E, R>, mode: {
40
+ readonly _tag: "Attached";
41
+ readonly socket: string;
42
+ readonly hubUrl: string;
43
+ readonly tokenFile: string;
44
+ } | {
45
+ readonly _tag: "Standalone";
46
+ readonly port: number;
47
+ readonly open: boolean;
48
+ }, launch: BrowserLaunch) => Effect.Effect<void, AppStartError, import("@knpkv/browser-pairing/launch").BrowserOpener | import("effect/Crypto").Crypto | FileSystem.FileSystem | import("effect/http/HttpClient").HttpClient | Path.Path | import("effect/Scope").Scope | import("effect/Stdio").Stdio | Exclude<R, ShellServices>>;
49
+ export { runApp } from "./main.js";
50
+ //# sourceMappingURL=node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,aAAa,EAA4B,MAAM,+BAA+B,CAAA;AAG5F,OAAO,EAAqB,MAAM,EAAE,UAAU,EAAE,KAAK,EAAU,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAanG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEpD,OAAO,EAAe,KAAK,gBAAgB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAEjF,OAAO,EAML,cAAc,EAGf,MAAM,YAAY,CAAA;AAInB,oGAAoG;AACpG,MAAM,WAAW,SAAS,CAAC,CAAC,EAAE,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;IACnC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,CAAA;IACpE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,EAAE,KAAK,EAAE,aAAa,CAAC,CAAA;IAC9G,uFAAuF;IACvF,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;CACjC;AAED,eAAO,MAAM,OAAO;;;;;;;IAOlB,CAAA;AACF,MAAM,MAAM,OAAO,GAAG,OAAO,OAAO,CAAC,IAAI,CAAA;AAEzC,uGAAuG;AACvG,eAAO,MAAM,WAAW,aACZ,gBAAgB,QACpB,aAAa,CAAC,MAAM,CAAC,OACtB,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,KAChD,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,aAAa,CAiCtC,CAAA;AAsJD,oFAAoF;AACpF,eAAO,MAAM,aAAa,GAA+C,CAAC,EAAE,CAAC;;;;;uRAwC3E,CAAA;AAmGF;;;GAGG;AACH,eAAO,MAAM,QAAQ,GAA0C,CAAC,EAAE,CAAC;;;;;;;;;mUAMoD,CAAA;AAEvH,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA"}