@knpkv/herdr-approvals 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 (133) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +22 -0
  3. package/dist/activity-history.d.ts +36 -0
  4. package/dist/activity-history.d.ts.map +1 -0
  5. package/dist/activity-history.js +233 -0
  6. package/dist/activity-history.js.map +1 -0
  7. package/dist/approval-app-view.d.ts +26 -0
  8. package/dist/approval-app-view.d.ts.map +1 -0
  9. package/dist/approval-app-view.js +79 -0
  10. package/dist/approval-app-view.js.map +1 -0
  11. package/dist/approval-client.d.ts +2 -0
  12. package/dist/approval-client.d.ts.map +1 -0
  13. package/dist/approval-client.js +520 -0
  14. package/dist/approval-client.js.map +1 -0
  15. package/dist/approval-sw.js +28 -0
  16. package/dist/approval-sw.js.map +7 -0
  17. package/dist/approval-url.d.ts +37 -0
  18. package/dist/approval-url.d.ts.map +1 -0
  19. package/dist/approval-url.js +37 -0
  20. package/dist/approval-url.js.map +1 -0
  21. package/dist/approval.js +188 -0
  22. package/dist/approval.js.map +7 -0
  23. package/dist/auth.d.ts +10 -0
  24. package/dist/auth.d.ts.map +1 -0
  25. package/dist/auth.js +14 -0
  26. package/dist/auth.js.map +1 -0
  27. package/dist/bin.d.ts +3 -0
  28. package/dist/bin.d.ts.map +1 -0
  29. package/dist/bin.js +47 -0
  30. package/dist/bin.js.map +1 -0
  31. package/dist/connect-entry.d.ts +2 -0
  32. package/dist/connect-entry.d.ts.map +1 -0
  33. package/dist/connect-entry.js +2 -0
  34. package/dist/connect-entry.js.map +1 -0
  35. package/dist/connect.js +188 -0
  36. package/dist/connect.js.map +7 -0
  37. package/dist/dashboard-model.d.ts +719 -0
  38. package/dist/dashboard-model.d.ts.map +1 -0
  39. package/dist/dashboard-model.js +83 -0
  40. package/dist/dashboard-model.js.map +1 -0
  41. package/dist/dashboard-view.d.ts +42 -0
  42. package/dist/dashboard-view.d.ts.map +1 -0
  43. package/dist/dashboard-view.js +194 -0
  44. package/dist/dashboard-view.js.map +1 -0
  45. package/dist/errors.d.ts +33 -0
  46. package/dist/errors.d.ts.map +1 -0
  47. package/dist/errors.js +12 -0
  48. package/dist/errors.js.map +1 -0
  49. package/dist/fleetctl-submission.d.ts +68 -0
  50. package/dist/fleetctl-submission.d.ts.map +1 -0
  51. package/dist/fleetctl-submission.js +31 -0
  52. package/dist/fleetctl-submission.js.map +1 -0
  53. package/dist/fleetctl.d.ts +22 -0
  54. package/dist/fleetctl.d.ts.map +1 -0
  55. package/dist/fleetctl.js +264 -0
  56. package/dist/fleetctl.js.map +1 -0
  57. package/dist/geist-latin-wght-normal.woff2 +0 -0
  58. package/dist/geist-mono-latin-wght-normal.woff2 +0 -0
  59. package/dist/http.d.ts +1512 -0
  60. package/dist/http.d.ts.map +1 -0
  61. package/dist/http.js +1653 -0
  62. package/dist/http.js.map +1 -0
  63. package/dist/index.css +2 -0
  64. package/dist/index.css.map +7 -0
  65. package/dist/index.d.ts +12 -0
  66. package/dist/index.d.ts.map +1 -0
  67. package/dist/index.js +12 -0
  68. package/dist/index.js.map +1 -0
  69. package/dist/internal/config-path.d.ts +3 -0
  70. package/dist/internal/config-path.d.ts.map +1 -0
  71. package/dist/internal/config-path.js +3 -0
  72. package/dist/internal/config-path.js.map +1 -0
  73. package/dist/internal/dashboard-pending-state.d.ts +49 -0
  74. package/dist/internal/dashboard-pending-state.d.ts.map +1 -0
  75. package/dist/internal/dashboard-pending-state.js +98 -0
  76. package/dist/internal/dashboard-pending-state.js.map +1 -0
  77. package/dist/internal/fleet-follow.d.ts +54 -0
  78. package/dist/internal/fleet-follow.d.ts.map +1 -0
  79. package/dist/internal/fleet-follow.js +10 -0
  80. package/dist/internal/fleet-follow.js.map +1 -0
  81. package/dist/internal/fleet-request.d.ts +4 -0
  82. package/dist/internal/fleet-request.d.ts.map +1 -0
  83. package/dist/internal/fleet-request.js +11 -0
  84. package/dist/internal/fleet-request.js.map +1 -0
  85. package/dist/internal/html.d.ts +3 -0
  86. package/dist/internal/html.d.ts.map +1 -0
  87. package/dist/internal/html.js +8 -0
  88. package/dist/internal/html.js.map +1 -0
  89. package/dist/internal/websocket.d.ts +4 -0
  90. package/dist/internal/websocket.d.ts.map +1 -0
  91. package/dist/internal/websocket.js +12 -0
  92. package/dist/internal/websocket.js.map +1 -0
  93. package/dist/model.d.ts +40 -0
  94. package/dist/model.d.ts.map +1 -0
  95. package/dist/model.js +53 -0
  96. package/dist/model.js.map +1 -0
  97. package/dist/operations.d.ts +72 -0
  98. package/dist/operations.d.ts.map +1 -0
  99. package/dist/operations.js +284 -0
  100. package/dist/operations.js.map +1 -0
  101. package/dist/push-policy.d.ts +3 -0
  102. package/dist/push-policy.d.ts.map +1 -0
  103. package/dist/push-policy.js +3 -0
  104. package/dist/push-policy.js.map +1 -0
  105. package/dist/push-sender.d.ts +18 -0
  106. package/dist/push-sender.d.ts.map +1 -0
  107. package/dist/push-sender.js +33 -0
  108. package/dist/push-sender.js.map +1 -0
  109. package/dist/push-subscription.d.ts +17 -0
  110. package/dist/push-subscription.d.ts.map +1 -0
  111. package/dist/push-subscription.js +62 -0
  112. package/dist/push-subscription.js.map +1 -0
  113. package/dist/push-worker.d.ts +20 -0
  114. package/dist/push-worker.d.ts.map +1 -0
  115. package/dist/push-worker.js +32 -0
  116. package/dist/push-worker.js.map +1 -0
  117. package/dist/pwa.d.ts +39 -0
  118. package/dist/pwa.d.ts.map +1 -0
  119. package/dist/pwa.js +51 -0
  120. package/dist/pwa.js.map +1 -0
  121. package/dist/shell-view.d.ts +20 -0
  122. package/dist/shell-view.d.ts.map +1 -0
  123. package/dist/shell-view.js +86 -0
  124. package/dist/shell-view.js.map +1 -0
  125. package/dist/store.d.ts +46 -0
  126. package/dist/store.d.ts.map +1 -0
  127. package/dist/store.js +291 -0
  128. package/dist/store.js.map +1 -0
  129. package/dist/work-checkpoint.d.ts +107 -0
  130. package/dist/work-checkpoint.d.ts.map +1 -0
  131. package/dist/work-checkpoint.js +37 -0
  132. package/dist/work-checkpoint.js.map +1 -0
  133. package/package.json +90 -0
@@ -0,0 +1,284 @@
1
+ import { AgentWorkLabel } from "@knpkv/herdr-connect";
2
+ import { makeCoordinatorLifecycle } from "@knpkv/herdr-coordinator";
3
+ import { AgentStableId, AgentSummary, FleetOperationError } from "@knpkv/herdr-fleet";
4
+ import { Effect, Path, Ref, Schema, Stream } from "effect";
5
+ import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
6
+ const HerdrAgentFields = {
7
+ agent_status: Schema.String,
8
+ cwd: Schema.String,
9
+ foreground_cwd: Schema.optionalKey(Schema.String),
10
+ name: Schema.optionalKey(Schema.NullOr(Schema.String)),
11
+ pane_id: Schema.String,
12
+ state_change_seq: Schema.Number.check(Schema.isInt(), Schema.isBetween({ maximum: Number.MAX_SAFE_INTEGER, minimum: 0 })),
13
+ tokens: Schema.optionalKey(Schema.Record(Schema.String, Schema.String))
14
+ };
15
+ const HerdrAgent = Schema.Struct({
16
+ agent: Schema.String,
17
+ ...HerdrAgentFields
18
+ });
19
+ const HerdrLaunchPendingAgent = Schema.Struct({
20
+ launch_pending: Schema.Literal(true),
21
+ ...HerdrAgentFields
22
+ });
23
+ const HerdrAgentEntry = Schema.Union([
24
+ HerdrLaunchPendingAgent,
25
+ HerdrAgent
26
+ ]);
27
+ const isHerdrLaunchPendingAgent = Schema.is(HerdrLaunchPendingAgent);
28
+ const isHerdrAgent = (agent) => !isHerdrLaunchPendingAgent(agent);
29
+ const HerdrAgents = Schema.Struct({
30
+ result: Schema.Struct({
31
+ agents: Schema.Array(HerdrAgentEntry)
32
+ })
33
+ });
34
+ const operationError = (operation) => (cause) => new FleetOperationError({ cause, detail: String(cause), operation });
35
+ /**
36
+ * Reserves transport-envelope headroom when one-byte control output expands to
37
+ * six JSON bytes beside the largest accepted job payload.
38
+ */
39
+ export const commandOutputMaxBytes = 128 * 1024;
40
+ const decodeLineage = Effect.fn("HostOperations.decodeLineage")(function* (tokens) {
41
+ const agentId = tokens?.agent_id;
42
+ const parentAgentId = tokens?.parent_agent_id;
43
+ const relation = tokens?.relation;
44
+ const version = tokens?.lineage_version;
45
+ const hasLineage = agentId !== undefined || parentAgentId !== undefined ||
46
+ relation !== undefined || version !== undefined;
47
+ if (!hasLineage) {
48
+ return {
49
+ agentId: null,
50
+ parentAgentId: null,
51
+ relation: null
52
+ };
53
+ }
54
+ if (version !== "hostd.agent-lineage.v1" || agentId === undefined) {
55
+ return yield* new FleetOperationError({
56
+ cause: tokens,
57
+ detail: "Herdr agent lineage metadata is incomplete or has an unsupported version",
58
+ operation: "herdr.agent_list.lineage"
59
+ });
60
+ }
61
+ const decodedAgentId = yield* Schema.decodeUnknownEffect(AgentStableId)(agentId).pipe(Effect.mapError(operationError("herdr.agent_list.lineage.agent_id")));
62
+ if (relation === "root" && parentAgentId === undefined) {
63
+ return {
64
+ agentId: decodedAgentId,
65
+ parentAgentId: null,
66
+ relation: null
67
+ };
68
+ }
69
+ if ((relation === "delegated" || relation === "pair" || relation === "review") &&
70
+ parentAgentId !== undefined) {
71
+ const decodedParent = yield* Schema.decodeUnknownEffect(AgentStableId)(parentAgentId).pipe(Effect.mapError(operationError("herdr.agent_list.lineage.parent_agent_id")));
72
+ return {
73
+ agentId: decodedAgentId,
74
+ parentAgentId: decodedParent,
75
+ relation
76
+ };
77
+ }
78
+ return yield* new FleetOperationError({
79
+ cause: tokens,
80
+ detail: "Herdr agent lineage relationship is malformed",
81
+ operation: "herdr.agent_list.lineage"
82
+ });
83
+ });
84
+ export const makeHostOperations = Effect.fn("HostOperations.make")(function* (config) {
85
+ const paths = yield* Path.Path;
86
+ const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
87
+ const collectOutput = (operation, stream) => stream.pipe(Stream.mapError(operationError(operation)), Stream.runFoldEffect(() => ({ bytes: 0, chunks: [] }), (output, chunk) => {
88
+ const bytes = output.bytes + chunk.byteLength;
89
+ return bytes > commandOutputMaxBytes
90
+ ? Effect.fail(new FleetOperationError({
91
+ cause: bytes,
92
+ detail: `command output exceeded ${commandOutputMaxBytes} bytes`,
93
+ operation
94
+ }))
95
+ : Effect.succeed({
96
+ bytes,
97
+ chunks: [...output.chunks, chunk]
98
+ });
99
+ }), Effect.flatMap((output) => Stream.fromIterable(output.chunks).pipe(Stream.decodeText(), Stream.mkString, Effect.mapError(operationError(operation)))));
100
+ const runCommand = Effect.fn("HostOperations.runCommand")(function* (operation, commandLine) {
101
+ const command = commandLine[0];
102
+ if (command === undefined) {
103
+ return yield* new FleetOperationError({
104
+ cause: commandLine,
105
+ detail: "configured command is empty",
106
+ operation
107
+ });
108
+ }
109
+ const child = ChildProcess.make(command, commandLine.slice(1), {
110
+ cwd: config.repository
111
+ });
112
+ return yield* Effect.scoped(spawner.spawn(child).pipe(Effect.mapError(operationError(operation)), Effect.flatMap((handle) => Effect.all({
113
+ exitCode: handle.exitCode.pipe(Effect.mapError(operationError(operation))),
114
+ stderr: collectOutput(operation, handle.stderr),
115
+ stdout: collectOutput(operation, handle.stdout)
116
+ }, { concurrency: "unbounded" }).pipe(Effect.flatMap(({ exitCode, stderr, stdout }) => Number(exitCode) === 0
117
+ ? Effect.succeed(stdout)
118
+ : Effect.fail(new FleetOperationError({
119
+ cause: exitCode,
120
+ detail: stderr.trim() === ""
121
+ ? `command exited with code ${String(exitCode)}`
122
+ : `command exited with code ${String(exitCode)}: ${stderr.trim()}`,
123
+ operation
124
+ }))))), Effect.timeoutOrElse({
125
+ duration: "30 minutes",
126
+ orElse: () => Effect.fail(new FleetOperationError({
127
+ cause: "30 minutes",
128
+ detail: "command timed out after 30 minutes",
129
+ operation
130
+ }))
131
+ }), Effect.map((output) => output.trim())));
132
+ });
133
+ const listAgents = Effect.fn("HostOperations.listAgents")(function* () {
134
+ return yield* runCommand("herdr.agent_list", [config.herdrCommand, "agent", "list"]).pipe(Effect.flatMap((output) => Effect.try({
135
+ try: () => Schema.decodeUnknownSync(HerdrAgents)(JSON.parse(output)),
136
+ catch: operationError("herdr.agent_list.decode")
137
+ })), Effect.flatMap((parsed) => Effect.forEach(parsed.result.agents.filter(isHerdrAgent), (agent) => {
138
+ return Effect.gen(function* () {
139
+ const basename = paths.basename(agent.foreground_cwd ?? agent.cwd);
140
+ const work = yield* Schema.decodeUnknownEffect(AgentWorkLabel)(basename === "" ? "root" : basename).pipe(Effect.mapError(operationError("herdr.agent_list.work")));
141
+ const lineage = yield* decodeLineage(agent.tokens);
142
+ return yield* Schema.decodeUnknownEffect(AgentSummary)({
143
+ agentId: lineage.agentId,
144
+ activityRevision: agent.state_change_seq,
145
+ kind: agent.agent,
146
+ name: agent.name ?? `${agent.agent}@${agent.pane_id}`,
147
+ paneId: agent.pane_id,
148
+ parentAgentId: lineage.parentAgentId,
149
+ relation: lineage.relation,
150
+ status: agent.agent_status,
151
+ work
152
+ }).pipe(Effect.mapError(operationError("herdr.agent_list.agent")));
153
+ });
154
+ })), Effect.map((agents) => ({ agents, available: true, error: null })), Effect.catchTag("FleetOperationError", (error) => Effect.succeed({
155
+ agents: [],
156
+ available: false,
157
+ error: `${error.operation}: ${error.detail}`
158
+ })));
159
+ });
160
+ const runCoordinatorCommand = Effect.fn("HostOperations.runCoordinatorCommand")(function* (operation, commandLine, workerStarted, jobId) {
161
+ const command = commandLine[0];
162
+ if (command === undefined) {
163
+ return yield* new FleetOperationError({
164
+ cause: commandLine,
165
+ detail: "configured coordinator command is empty",
166
+ operation
167
+ });
168
+ }
169
+ const child = ChildProcess.make(command, commandLine.slice(1), {
170
+ cwd: config.repository
171
+ });
172
+ const validatedWorkerStarted = (identity) => {
173
+ const configured = config.machines.some(({ host }) => host.toLowerCase() === identity.host.toLowerCase());
174
+ return configured
175
+ ? workerStarted(identity)
176
+ : Effect.fail(new FleetOperationError({
177
+ cause: identity.host,
178
+ detail: "coordinator worker identity names an unknown fleet host",
179
+ operation: `${operation}.worker_host`
180
+ }));
181
+ };
182
+ return yield* Effect.scoped(spawner.spawn(child).pipe(Effect.mapError(operationError(operation)), Effect.flatMap((handle) => Effect.gen(function* () {
183
+ const lifecycle = makeCoordinatorLifecycle(jobId, validatedWorkerStarted);
184
+ const stdoutBytes = yield* Ref.make(0);
185
+ const stdout = handle.stdout.pipe(Stream.mapEffect((chunk) => Ref.updateAndGet(stdoutBytes, (bytes) => bytes + chunk.byteLength).pipe(Effect.flatMap((bytes) => bytes > commandOutputMaxBytes
186
+ ? Effect.fail(new FleetOperationError({
187
+ cause: bytes,
188
+ detail: `command output exceeded ${commandOutputMaxBytes} bytes`,
189
+ operation
190
+ }))
191
+ : Effect.succeed(chunk)))), Stream.decodeText(), Stream.splitLines, Stream.runForEach(lifecycle.accept), Effect.mapError(operationError(`${operation}.lifecycle`)));
192
+ const { exitCode, stderr } = yield* Effect.all({
193
+ exitCode: handle.exitCode.pipe(Effect.mapError(operationError(operation))),
194
+ stdout,
195
+ stderr: collectOutput(operation, handle.stderr)
196
+ }, { concurrency: "unbounded" });
197
+ if (Number(exitCode) !== 0) {
198
+ return yield* new FleetOperationError({
199
+ cause: exitCode,
200
+ detail: stderr.trim() === ""
201
+ ? `command exited with code ${String(exitCode)}`
202
+ : `command exited with code ${String(exitCode)}: ${stderr.trim()}`,
203
+ operation
204
+ });
205
+ }
206
+ const result = yield* lifecycle.finish().pipe(Effect.mapError(operationError(`${operation}.lifecycle`)));
207
+ return result.reply;
208
+ })), Effect.timeoutOrElse({
209
+ duration: "30 minutes",
210
+ orElse: () => Effect.fail(new FleetOperationError({
211
+ cause: "30 minutes",
212
+ detail: "command timed out after 30 minutes",
213
+ operation
214
+ }))
215
+ })));
216
+ });
217
+ const inspect = Effect.fn("HostOperations.inspect")(function* () {
218
+ const { branch, revision, status } = yield* Effect.all({
219
+ branch: runCommand("git.branch", ["git", "branch", "--show-current"]),
220
+ revision: runCommand("git.revision", ["git", "rev-parse", "HEAD"]),
221
+ status: runCommand("git.status", ["git", "status", "--porcelain"])
222
+ });
223
+ return {
224
+ applyConfigured: config.applyCommand !== null,
225
+ branch,
226
+ dirty: status !== "",
227
+ repository: config.repository,
228
+ revision
229
+ };
230
+ });
231
+ const runPayload = (payload, workerStarted, jobId) => {
232
+ switch (payload.kind) {
233
+ case "nix.check":
234
+ return runCommand("nix.check", config.checkCommand);
235
+ case "nix.apply":
236
+ return config.applyCommand === null
237
+ ? Effect.fail(new FleetOperationError({
238
+ cause: config.host,
239
+ detail: "Nix apply is not configured on this host",
240
+ operation: "nix.apply"
241
+ }))
242
+ : runCommand("nix.apply", [...config.applyCommand, payload.ref]);
243
+ case "agent.delegate":
244
+ return runCoordinatorCommand("agent.delegate", [
245
+ ...config.coordinatorCommand,
246
+ "delegate",
247
+ jobId,
248
+ JSON.stringify(payload)
249
+ ], workerStarted, jobId);
250
+ case "agent.message":
251
+ return runCommand("agent.message", [
252
+ config.herdrCommand,
253
+ "agent",
254
+ "prompt",
255
+ payload.session,
256
+ payload.message,
257
+ "--wait",
258
+ "--timeout",
259
+ "900000"
260
+ ]);
261
+ }
262
+ };
263
+ const runLocal = (payload) => config.browserMcpRecoverCommand === null
264
+ ? Effect.fail(new FleetOperationError({
265
+ cause: payload.kind,
266
+ detail: "browser MCP recovery is not configured on this host",
267
+ operation: payload.kind
268
+ }))
269
+ : runCommand(payload.kind, config.browserMcpRecoverCommand);
270
+ const runCoordinatorChat = (payload, workerStarted, jobId) => runCoordinatorCommand("agent.delegate.chat", [
271
+ ...config.coordinatorCommand,
272
+ "chat",
273
+ jobId,
274
+ JSON.stringify(payload)
275
+ ], workerStarted, jobId);
276
+ return {
277
+ inspect,
278
+ listAgents,
279
+ run: runPayload,
280
+ runLocal,
281
+ runCoordinatorChat
282
+ };
283
+ });
284
+ //# sourceMappingURL=operations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"operations.js","sourceRoot":"","sources":["../src/operations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare const pushDeliveryTtlSeconds = 60;
2
+ export declare const pushDeliveryTtlMillis: number;
3
+ //# sourceMappingURL=push-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-policy.d.ts","sourceRoot":"","sources":["../src/push-policy.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,KAAK,CAAA;AACxC,eAAO,MAAM,qBAAqB,QAAiC,CAAA"}
@@ -0,0 +1,3 @@
1
+ export const pushDeliveryTtlSeconds = 60;
2
+ export const pushDeliveryTtlMillis = pushDeliveryTtlSeconds * 1_000;
3
+ //# sourceMappingURL=push-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-policy.js","sourceRoot":"","sources":["../src/push-policy.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,CAAA;AACxC,MAAM,CAAC,MAAM,qBAAqB,GAAG,sBAAsB,GAAG,KAAK,CAAA"}
@@ -0,0 +1,18 @@
1
+ import { Effect } from "effect";
2
+ import { type ApprovalAppStoreError, PushDeliveryError } from "./errors.js";
3
+ import type { VapidKeyPair } from "./model.js";
4
+ import type { ApprovalAppStore } from "./store.js";
5
+ export declare const generateVapidKeys: () => VapidKeyPair;
6
+ export declare const makePushSender: (keys: VapidKeyPair, subject: string, store: ApprovalAppStore, allowedOrigins: ReadonlyArray<string>) => (subscription: {
7
+ readonly endpoint: string;
8
+ readonly expirationTime: number | null;
9
+ readonly keys: {
10
+ readonly auth: string;
11
+ readonly p256dh: string;
12
+ };
13
+ }, payload: {
14
+ readonly host: string;
15
+ readonly jobId: string;
16
+ readonly pendingCount: number | null;
17
+ }) => Effect.Effect<void, ApprovalAppStoreError | PushDeliveryError | import("./errors.js").PushEndpointNotAllowedError, never>;
18
+ //# sourceMappingURL=push-sender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-sender.d.ts","sourceRoot":"","sources":["../src/push-sender.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAkB,MAAM,QAAQ,CAAA;AAE/C,OAAO,EAAE,KAAK,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC3E,OAAO,KAAK,EAA+C,YAAY,EAAE,MAAM,YAAY,CAAA;AAG3F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,eAAO,MAAM,iBAAiB,QAAO,YAA2C,CAAA;AAIhF,eAAO,MAAM,cAAc,SACnB,YAAY,WACT,MAAM,SACR,gBAAgB,kBACP,aAAa,CAAC,MAAM,CAAC;;;;;;;;;;;+HAsCnC,CAAA"}
@@ -0,0 +1,33 @@
1
+ import { Effect, Result, Schema } from "effect";
2
+ import webPush from "web-push";
3
+ import { PushDeliveryError } from "./errors.js";
4
+ import { pushDeliveryTtlSeconds } from "./push-policy.js";
5
+ import { validatePushEndpoint } from "./push-subscription.js";
6
+ export const generateVapidKeys = () => webPush.generateVAPIDKeys();
7
+ const WebPushFailure = Schema.Struct({ statusCode: Schema.Number });
8
+ export const makePushSender = (keys, subject, store, allowedOrigins) => Effect.fn("PushSender.send")(function* (subscription, payload) {
9
+ yield* validatePushEndpoint(subscription.endpoint, allowedOrigins);
10
+ yield* Effect.tryPromise({
11
+ try: () => webPush.sendNotification(subscription, JSON.stringify(payload), {
12
+ TTL: pushDeliveryTtlSeconds,
13
+ timeout: 10_000,
14
+ urgency: "high",
15
+ vapidDetails: {
16
+ privateKey: keys.privateKey,
17
+ publicKey: keys.publicKey,
18
+ subject
19
+ }
20
+ }),
21
+ catch: (cause) => {
22
+ const decoded = Schema.decodeUnknownResult(WebPushFailure)(cause);
23
+ return new PushDeliveryError({
24
+ operation: "webpush.send",
25
+ statusCode: Result.isSuccess(decoded) ? decoded.success.statusCode : null,
26
+ cause
27
+ });
28
+ }
29
+ }).pipe(Effect.catchTag("PushDeliveryError", (error) => error.statusCode === 404 || error.statusCode === 410
30
+ ? store.deleteSubscriptionPrivileged(subscription.endpoint)
31
+ : Effect.fail(error)));
32
+ });
33
+ //# sourceMappingURL=push-sender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-sender.js","sourceRoot":"","sources":["../src/push-sender.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,OAAO,MAAM,UAAU,CAAA;AAC9B,OAAO,EAA8B,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAE3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAG7D,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAiB,EAAE,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAA;AAEhF,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAA;AAEnE,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,IAAkB,EAClB,OAAe,EACf,KAAuB,EACvB,cAAqC,EACrC,EAAE,CACF,MAAM,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,QAAQ,CAAC,EACpC,YAAoC,EACpC,OAA4B;IAE5B,KAAK,CAAC,CAAC,oBAAoB,CAAC,YAAY,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAA;IAClE,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;QACvB,GAAG,EAAE,GAAG,EAAE,CACR,OAAO,CAAC,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;YAC9D,GAAG,EAAE,sBAAsB;YAC3B,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,MAAM;YACf,YAAY,EAAE;gBACZ,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,OAAO;aACR;SACF,CAAC;QACJ,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE;YACf,MAAM,OAAO,GAAG,MAAM,CAAC,mBAAmB,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAA;YACjE,OAAO,IAAI,iBAAiB,CAAC;gBAC3B,SAAS,EAAE,cAAc;gBACzB,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI;gBACzE,KAAK;aACN,CAAC,CAAA;QACJ,CAAC;KACF,CAAC,CAAC,IAAI,CACL,MAAM,CAAC,QAAQ,CACb,mBAAmB,EACnB,CACE,KAAK,EAC2D,EAAE,CAClE,KAAK,CAAC,UAAU,KAAK,GAAG,IAAI,KAAK,CAAC,UAAU,KAAK,GAAG;QAClD,CAAC,CAAC,KAAK,CAAC,4BAA4B,CAAC,YAAY,CAAC,QAAQ,CAAC;QAC3D,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CACzB,CACF,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,17 @@
1
+ import { Effect } from "effect";
2
+ import { PushEndpointNotAllowedError, PushSubscriptionCleanupError } from "./errors.js";
3
+ export declare const validatePushEndpoint: (endpoint: string, allowedOrigins: ReadonlyArray<string>) => Effect.Effect<string, PushEndpointNotAllowedError, never>;
4
+ export interface OwnedPushSubscription {
5
+ readonly unsubscribe: () => Promise<boolean>;
6
+ }
7
+ export interface CurrentPushSubscription extends OwnedPushSubscription {
8
+ readonly options: {
9
+ readonly applicationServerKey: ArrayBuffer | null;
10
+ };
11
+ }
12
+ export declare const reconcileExistingPushSubscription: <Subscription, CheckError, CheckRequirements, RegisterResult, RegisterError, RegisterRequirements>(subscription: Subscription | null, isRegistered: (subscription: Subscription) => Effect.Effect<boolean, CheckError, CheckRequirements>, register: (subscription: Subscription) => Effect.Effect<RegisterResult, RegisterError, RegisterRequirements>) => Effect.Effect<boolean, CheckError | RegisterError, CheckRequirements | RegisterRequirements>;
13
+ export declare const reconcilePushSubscriptionState: <Subscription, CheckError, CheckRequirements, RegisterResult, RegisterError, RegisterRequirements>(permission: "default" | "denied" | "granted", subscription: Subscription | null, isRegistered: (subscription: Subscription) => Effect.Effect<boolean, CheckError, CheckRequirements>, register: (subscription: Subscription) => Effect.Effect<RegisterResult, RegisterError, RegisterRequirements>) => Effect.Effect<"denied", never, never> | Effect.Effect<"disabled" | "enabled", CheckError | RegisterError, CheckRequirements | RegisterRequirements>;
14
+ export declare const registerNewPushSubscription: <Subscription extends OwnedPushSubscription, A, AcquireError, AcquireRequirements, RegisterError, RegisterRequirements>(acquire: Effect.Effect<Subscription, AcquireError, AcquireRequirements>, register: (subscription: Subscription) => Effect.Effect<A, RegisterError, RegisterRequirements>) => Effect.Effect<A, AcquireError | RegisterError | PushSubscriptionCleanupError, AcquireRequirements | RegisterRequirements>;
15
+ export declare const reconcileCurrentPushSubscription: <Subscription extends CurrentPushSubscription, CheckError, CheckRequirements, RegisterResult, RegisterError, RegisterRequirements, RemoveResult, RemoveError, RemoveRequirements, AcquireError, AcquireRequirements>(subscription: Subscription, expectedApplicationServerKey: ArrayBuffer, acquire: Effect.Effect<Subscription, AcquireError, AcquireRequirements>, isRegistered: (subscription: Subscription) => Effect.Effect<boolean, CheckError, CheckRequirements>, register: (subscription: Subscription) => Effect.Effect<RegisterResult, RegisterError, RegisterRequirements>, removeServerRegistration: (subscription: Subscription) => Effect.Effect<RemoveResult, RemoveError, RemoveRequirements>) => Effect.Effect<boolean, AcquireError | CheckError | RegisterError | RemoveError | PushSubscriptionCleanupError, AcquireRequirements | CheckRequirements | RegisterRequirements | RemoveRequirements>;
16
+ export declare const unregisterPushSubscription: <UnsubscribeError, UnsubscribeRequirements, RemoveResult, RemoveError, RemoveRequirements>(unsubscribe: Effect.Effect<boolean, UnsubscribeError, UnsubscribeRequirements>, removeServerRegistration: Effect.Effect<RemoveResult, RemoveError, RemoveRequirements>) => Effect.Effect<RemoveResult, RemoveError | UnsubscribeError | PushSubscriptionCleanupError, RemoveRequirements | UnsubscribeRequirements>;
17
+ //# sourceMappingURL=push-subscription.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-subscription.d.ts","sourceRoot":"","sources":["../src/push-subscription.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAO,MAAM,QAAQ,CAAA;AACpC,OAAO,EAAE,2BAA2B,EAAE,4BAA4B,EAAE,MAAM,aAAa,CAAA;AAEvF,eAAO,MAAM,oBAAoB,aACrB,MAAM,kBACA,aAAa,CAAC,MAAM,CAAC,8DAsBpC,CAAA;AAEH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;CAC7C;AAED,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,QAAQ,CAAC,OAAO,EAAE;QAChB,QAAQ,CAAC,oBAAoB,EAAE,WAAW,GAAG,IAAI,CAAA;KAClD,CAAA;CACF;AAYD,eAAO,MAAM,iCAAiC,GAC5C,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,oBAAoB,gBAEN,YAAY,GAAG,IAAI,gBACnB,CACZ,YAAY,EAAE,YAAY,KACvB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,iBAAiB,CAAC,YAChD,CACR,YAAY,EAAE,YAAY,KACvB,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,aAAa,EAAE,oBAAoB,CAAC,iGAUpE,CAAA;AAEL,eAAO,MAAM,8BAA8B,GACzC,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,oBAAoB,cAER,SAAS,GAAG,QAAQ,GAAG,SAAS,gBAC9B,YAAY,GAAG,IAAI,gBACnB,CACZ,YAAY,EAAE,YAAY,KACvB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,iBAAiB,CAAC,YAChD,CACR,YAAY,EAAE,YAAY,KACvB,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,aAAa,EAAE,oBAAoB,CAAC,wJAYpE,CAAA;AAEL,eAAO,MAAM,2BAA2B,GACtC,YAAY,SAAS,qBAAqB,EAC1C,CAAC,EACD,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACb,oBAAoB,oGAIJ,YAAY,KACvB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,aAAa,EAAE,oBAAoB,CAAC,8HAqB1D,CAAA;AAEF,eAAO,MAAM,gCAAgC,GAG3C,YAAY,SAAS,uBAAuB,EAC5C,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,YAAY,EACZ,mBAAmB,+KAMH,YAAY,KACvB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,iBAAiB,CAAC,2BAE1C,YAAY,KACvB,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,aAAa,EAAE,oBAAoB,CAAC,2CAEvD,YAAY,KACvB,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,WAAW,EAAE,kBAAkB,CAAC,wMA0BjE,CAAA;AAEF,eAAO,MAAM,0BAA0B,GACrC,gBAAgB,EAChB,uBAAuB,EACvB,YAAY,EACZ,WAAW,EACX,kBAAkB,qTAwBlB,CAAA"}
@@ -0,0 +1,62 @@
1
+ import { Effect, Ref } from "effect";
2
+ import { PushEndpointNotAllowedError, PushSubscriptionCleanupError } from "./errors.js";
3
+ export const validatePushEndpoint = (endpoint, allowedOrigins) => Effect.try({
4
+ try: () => new URL(endpoint).origin,
5
+ catch: () => new PushEndpointNotAllowedError({ origin: "invalid" })
6
+ }).pipe(Effect.flatMap((origin) => Effect.forEach(allowedOrigins, (allowedOrigin) => Effect.try({
7
+ try: () => new URL(allowedOrigin).origin,
8
+ catch: () => new PushEndpointNotAllowedError({ origin: allowedOrigin })
9
+ })).pipe(Effect.flatMap((canonicalOrigins) => canonicalOrigins.includes(origin)
10
+ ? Effect.succeed(endpoint)
11
+ : Effect.fail(new PushEndpointNotAllowedError({ origin }))))));
12
+ const applicationServerKeysEqual = (current, expected) => {
13
+ if (current === null || current.byteLength !== expected.byteLength)
14
+ return false;
15
+ const currentBytes = new Uint8Array(current);
16
+ const expectedBytes = new Uint8Array(expected);
17
+ return currentBytes.every((byte, index) => byte === expectedBytes[index]);
18
+ };
19
+ export const reconcileExistingPushSubscription = (subscription, isRegistered, register) => subscription === null
20
+ ? Effect.succeed(false)
21
+ : isRegistered(subscription).pipe(Effect.flatMap((registered) => registered
22
+ ? Effect.succeed(true)
23
+ : register(subscription).pipe(Effect.as(true))));
24
+ export const reconcilePushSubscriptionState = (permission, subscription, isRegistered, register) => permission === "denied"
25
+ ? Effect.succeed("denied")
26
+ : reconcileExistingPushSubscription(subscription, isRegistered, register).pipe(Effect.map((registered) => registered ? "enabled" : "disabled"));
27
+ export const registerNewPushSubscription = Effect.fn("PushSubscription.registerNew")(function* (acquire, register) {
28
+ const retained = yield* Ref.make(false);
29
+ return yield* Effect.acquireUseRelease(acquire, (subscription) => register(subscription).pipe(Effect.tap(() => Ref.set(retained, true))), (subscription) => Ref.get(retained).pipe(Effect.flatMap((keep) => keep
30
+ ? Effect.void
31
+ : Effect.tryPromise({
32
+ try: () => subscription.unsubscribe(),
33
+ catch: (cause) => new PushSubscriptionCleanupError({ cause })
34
+ }).pipe(Effect.asVoid))));
35
+ });
36
+ export const reconcileCurrentPushSubscription = Effect.fn("PushSubscription.reconcileCurrent")(function* (subscription, expectedApplicationServerKey, acquire, isRegistered, register, removeServerRegistration) {
37
+ if (applicationServerKeysEqual(subscription.options.applicationServerKey, expectedApplicationServerKey)) {
38
+ return yield* reconcileExistingPushSubscription(subscription, isRegistered, register);
39
+ }
40
+ yield* removeServerRegistration(subscription);
41
+ const unsubscribed = yield* Effect.tryPromise({
42
+ try: () => subscription.unsubscribe(),
43
+ catch: (cause) => new PushSubscriptionCleanupError({ cause })
44
+ });
45
+ if (!unsubscribed) {
46
+ return yield* new PushSubscriptionCleanupError({
47
+ cause: "browser push subscription remained active after key rotation"
48
+ });
49
+ }
50
+ yield* registerNewPushSubscription(acquire, register);
51
+ return true;
52
+ });
53
+ export const unregisterPushSubscription = Effect.fn("PushSubscription.unregister")(function* (unsubscribe, removeServerRegistration) {
54
+ const unsubscribed = yield* unsubscribe;
55
+ if (!unsubscribed) {
56
+ return yield* new PushSubscriptionCleanupError({
57
+ cause: "browser push subscription remained active"
58
+ });
59
+ }
60
+ return yield* removeServerRegistration;
61
+ });
62
+ //# sourceMappingURL=push-subscription.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-subscription.js","sourceRoot":"","sources":["../src/push-subscription.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { Duration } from "effect";
2
+ import { Effect } from "effect";
3
+ import type { ApprovalNotificationCandidate, ApprovalPushPayload, PushSubscriptionRecord } from "./model.js";
4
+ import type { ApprovalAppStore } from "./store.js";
5
+ export type ApprovalNotificationBatch = {
6
+ readonly candidates: ReadonlyArray<ApprovalNotificationCandidate>;
7
+ readonly pendingCount: number | null;
8
+ };
9
+ type PushPassOptions<LoadError, SendError, LoadServices, SendServices> = {
10
+ readonly allowedPushOrigins: ReadonlyArray<string>;
11
+ readonly allowedUsers: ReadonlyArray<string>;
12
+ readonly loadCandidates: () => Effect.Effect<ApprovalNotificationBatch, LoadError, LoadServices>;
13
+ readonly now?: Effect.Effect<number>;
14
+ readonly send: (target: PushSubscriptionRecord, payload: ApprovalPushPayload) => Effect.Effect<void, SendError, SendServices>;
15
+ readonly store: ApprovalAppStore;
16
+ };
17
+ export declare const runPushPass: <LoadError, SendError, LoadServices, SendServices>(options: PushPassOptions<LoadError, SendError, LoadServices, SendServices>) => Effect.Effect<void, LoadError | import("./errors.ts").ApprovalAppStoreError, LoadServices | SendServices>;
18
+ export declare const makePushWorker: <LoadError, SendError, LoadServices, SendServices>(options: PushPassOptions<LoadError, SendError, LoadServices, SendServices>, interval?: Duration.Input) => Effect.Effect<number, never, LoadServices | SendServices>;
19
+ export {};
20
+ //# sourceMappingURL=push-worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-worker.d.ts","sourceRoot":"","sources":["../src/push-worker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AACtC,OAAO,EAAS,MAAM,EAAY,MAAM,QAAQ,CAAA;AAChD,OAAO,KAAK,EAAE,6BAA6B,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAG5G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,6BAA6B,CAAC,CAAA;IACjE,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CACrC,CAAA;AAED,KAAK,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,IAAI;IACvE,QAAQ,CAAC,kBAAkB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IAClD,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IAC5C,QAAQ,CAAC,cAAc,EAAE,MAAM,MAAM,CAAC,MAAM,CAC1C,yBAAyB,EACzB,SAAS,EACT,YAAY,CACb,CAAA;IACD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACpC,QAAQ,CAAC,IAAI,EAAE,CACb,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,mBAAmB,KACzB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,CAAC,CAAA;IACjD,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;CACjC,CAAA;AAED,eAAO,MAAM,WAAW,GACtB,SAAS,EACT,SAAS,EACT,YAAY,EACZ,YAAY,0LAkEZ,CAAA;AAEF,eAAO,MAAM,cAAc,GACzB,SAAS,EACT,SAAS,EACT,YAAY,EACZ,YAAY,WAEH,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,CAAC,aAChE,QAAQ,CAAC,KAAK,8DAMvB,CAAA"}
@@ -0,0 +1,32 @@
1
+ import { Clock, Effect, Schedule } from "effect";
2
+ import { pushDeliveryTtlMillis } from "./push-policy.js";
3
+ import { validatePushEndpoint } from "./push-subscription.js";
4
+ export const runPushPass = Effect.fn("PushWorker.runPass")(function* (options) {
5
+ const { candidates, pendingCount } = yield* options.loadCandidates();
6
+ const subscriptions = yield* options.store.listSubscriptions();
7
+ const timestamp = yield* (options.now ?? Clock.currentTimeMillis);
8
+ yield* Effect.forEach(candidates, (candidate) => Effect.gen(function* () {
9
+ const payload = {
10
+ host: candidate.host,
11
+ jobId: candidate.jobId,
12
+ pendingCount
13
+ };
14
+ yield* Effect.forEach(subscriptions, (target) => Effect.gen(function* () {
15
+ if (target.owner === undefined ||
16
+ !options.allowedUsers.includes(target.owner)) {
17
+ yield* options.store.deleteSubscriptionPrivileged(target.endpoint);
18
+ return;
19
+ }
20
+ const allowed = yield* validatePushEndpoint(target.endpoint, options.allowedPushOrigins).pipe(Effect.as(true), Effect.catchTag("PushEndpointNotAllowedError", () => options.store.deleteSubscriptionPrivileged(target.endpoint).pipe(Effect.as(false))));
21
+ if (!allowed)
22
+ return;
23
+ const delivered = yield* options.store.hasDelivered(candidate.host, candidate.jobId, target.endpoint, timestamp - pushDeliveryTtlMillis, pendingCount !== null);
24
+ if (delivered)
25
+ return;
26
+ yield* options.send(target, payload);
27
+ yield* options.store.recordDeliveryIfSubscriptionMatches(candidate.host, candidate.jobId, target, target.owner, timestamp, pendingCount !== null);
28
+ }).pipe(Effect.tapError((error) => Effect.logError("PushWorker.delivery_failed", error)), Effect.ignore), { discard: true });
29
+ }), { discard: true });
30
+ });
31
+ export const makePushWorker = (options, interval = "15 seconds") => runPushPass(options).pipe(Effect.tapError((error) => Effect.logError("PushWorker.pass_failed", error)), Effect.ignore, Effect.repeat(Schedule.spaced(interval)));
32
+ //# sourceMappingURL=push-worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-worker.js","sourceRoot":"","sources":["../src/push-worker.ts"],"names":[],"mappings":"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"}
package/dist/pwa.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ import { Result, Schema } from "effect";
2
+ import { ApprovalNotificationCandidate, type ApprovalPushPayload } from "./model.js";
3
+ declare const ApprovalDeepLinkError_base: Schema.Class<ApprovalDeepLinkError, Schema.TaggedStruct<"ApprovalDeepLinkError", {
4
+ readonly cause: Schema.Defect;
5
+ }>, import("effect/Cause").YieldableError>;
6
+ export declare class ApprovalDeepLinkError extends ApprovalDeepLinkError_base {
7
+ }
8
+ export type ApprovalWorkerRegistration = {
9
+ readonly scope: string;
10
+ readonly showNotification: (title: string, options: {
11
+ readonly badge: string;
12
+ readonly body: string;
13
+ readonly data: ApprovalPushPayload;
14
+ readonly icon: string;
15
+ readonly tag: string;
16
+ }) => Promise<void>;
17
+ };
18
+ export type ApprovalWorkerClient = {
19
+ readonly focus: () => Promise<void>;
20
+ readonly navigate: (url: string) => Promise<void>;
21
+ readonly url: string;
22
+ };
23
+ export type ApprovalWorkerClients = {
24
+ readonly matchAll: () => Promise<ReadonlyArray<ApprovalWorkerClient>>;
25
+ readonly openWindow: (url: string) => Promise<void>;
26
+ };
27
+ export declare const showApprovalNotification: (registration: ApprovalWorkerRegistration, setBadge: (count: number) => Promise<void>, payload: ApprovalPushPayload) => Promise<void>;
28
+ export declare const approvalDeepLink: (canonicalUrl: string, payload: ApprovalNotificationCandidate) => string;
29
+ export declare const readApprovalDeepLink: (search: string) => Result.Result<null, never> | Result.Result<never, ApprovalDeepLinkError> | Result.Result<{
30
+ readonly host: string;
31
+ readonly jobId: string;
32
+ }, never>;
33
+ export declare const matchesApprovalDeepLink: (dataset: {
34
+ readonly approvalHost?: string;
35
+ readonly approvalJob?: string;
36
+ }, target: ApprovalNotificationCandidate) => boolean;
37
+ export declare const handleNotificationClick: (clients: ApprovalWorkerClients, deepLinkUrl: string) => Promise<void>;
38
+ export {};
39
+ //# sourceMappingURL=pwa.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pwa.d.ts","sourceRoot":"","sources":["../src/pwa.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,EAAE,6BAA6B,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAA;;;;AAEpF,qBAAa,qBAAsB,SAAQ,0BAG1C;CAAG;AAEJ,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,gBAAgB,EAAE,CACzB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;QACP,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAA;QAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KACrB,KACE,OAAO,CAAC,IAAI,CAAC,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACjD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC,CAAA;IACrE,QAAQ,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACpD,CAAA;AAED,eAAO,MAAM,wBAAwB,iBACrB,0BAA0B,YAC9B,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,WACjC,mBAAmB,KAC3B,OAAO,CAAC,IAAI,CAed,CAAA;AAED,eAAO,MAAM,gBAAgB,iBACb,MAAM,WACX,6BAA6B,KACrC,MAMF,CAAA;AAED,eAAO,MAAM,oBAAoB,WAAY,MAAM;;;SASlD,CAAA;AAED,eAAO,MAAM,uBAAuB,YACzB;IACP,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAC9B,UACO,6BAA6B,KACpC,OAEmC,CAAA;AAEtC,eAAO,MAAM,uBAAuB,YACzB,qBAAqB,eACjB,MAAM,KAClB,OAAO,CAAC,IAAI,CAUd,CAAA"}