@knpkv/jcf-web 0.2.0 → 0.4.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.
- package/dist/main.js +7 -5
- package/dist/main.js.map +1 -1
- package/dist/server/Api.d.ts +121 -121
- package/dist/server/HttpApplication.d.ts +16 -5
- package/dist/server/HttpApplication.js +20 -53
- package/dist/server/HttpApplication.js.map +1 -1
- package/dist/server/OwnerSession.d.ts +15 -60
- package/dist/server/OwnerSession.js +17 -209
- package/dist/server/OwnerSession.js.map +1 -1
- package/dist/server/Server.d.ts +4 -3
- package/dist/server/Server.js +4 -3
- package/dist/server/Server.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
package/dist/main.js
CHANGED
|
@@ -5,25 +5,27 @@
|
|
|
5
5
|
* @module
|
|
6
6
|
*/
|
|
7
7
|
import { NodeRuntime, NodeServices } from "@effect/platform-node";
|
|
8
|
+
import { loopbackOrigin } from "@knpkv/browser-pairing/owner-session";
|
|
8
9
|
import { Deferred, Effect, Fiber, Layer, Option } from "effect";
|
|
9
10
|
import * as Stdio from "effect/Stdio";
|
|
10
11
|
import * as Stream from "effect/Stream";
|
|
11
|
-
import {
|
|
12
|
+
import { makeOwnerSession } from "./server/OwnerSession.js";
|
|
12
13
|
import { makeServer, Port, PublicOrigin } from "./server/Server.js";
|
|
13
14
|
const run = Effect.gen(function* () {
|
|
14
15
|
const stdio = yield* Stdio.Stdio;
|
|
15
16
|
const port = yield* Port.pipe(Effect.orDie);
|
|
16
17
|
const configuredOrigin = yield* PublicOrigin.pipe(Effect.orDie);
|
|
17
|
-
const authorityOrigin =
|
|
18
|
+
const authorityOrigin = loopbackOrigin("127.0.0.1", port);
|
|
18
19
|
// One origin decision: the URL that gets printed is the same origin every request is checked
|
|
19
20
|
// against, so a dev proxy in front of the server cannot be advertised and then rejected.
|
|
20
|
-
const security = yield*
|
|
21
|
+
const security = yield* makeOwnerSession(authorityOrigin, Option.getOrUndefined(configuredOrigin)).pipe(Effect.orDie);
|
|
21
22
|
const ready = yield* Deferred.make();
|
|
22
23
|
const server = yield* Layer.launch(makeServer({ port, ready, security })).pipe(Effect.forkChild({ startImmediately: true }));
|
|
23
|
-
|
|
24
|
+
// The server only ends this race by failing; until it is listening there is no link to print.
|
|
25
|
+
const url = yield* Effect.raceFirst(Deferred.await(ready), Fiber.join(server).pipe(Effect.andThen(Effect.never)));
|
|
24
26
|
// On stdout and nowhere else: this line is the credential. It is not logged, so it cannot end up
|
|
25
27
|
// in a log file that outlives the process that minted it.
|
|
26
|
-
yield* Stream.make(`jcf week view: ${
|
|
28
|
+
yield* Stream.make(`jcf week view: ${url}\n`).pipe(Stream.run(stdio.stdout()));
|
|
27
29
|
return yield* Fiber.join(server);
|
|
28
30
|
});
|
|
29
31
|
// Executable entry point: the host platform is provided once for this process.
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA;;;;GAIG;AACH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/D,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA;;;;GAIG;AACH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAA;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/D,OAAO,KAAK,KAAK,MAAM,cAAc,CAAA;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEnE,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAA;IAChC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,gBAAgB,GAAG,KAAK,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC/D,MAAM,eAAe,GAAG,cAAc,CAAC,WAAW,EAAE,IAAI,CAAC,CAAA;IAEzD,6FAA6F;IAC7F,yFAAyF;IACzF,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,gBAAgB,CACtC,eAAe,EACf,MAAM,CAAC,cAAc,CAAC,gBAAgB,CAAC,CACxC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAEpB,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAU,CAAA;IAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAC5E,MAAM,CAAC,SAAS,CAAC,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAC7C,CAAA;IACD,8FAA8F;IAC9F,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACjH,iGAAiG;IACjG,0DAA0D;IAC1D,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC,IAAI,CAChD,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAC3B,CAAA;IACD,OAAO,KAAK,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;AAClC,CAAC,CAAC,CAAA;AAEF,+EAA+E;AAC/E,wDAAwD;AACxD,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA"}
|
package/dist/server/Api.d.ts
CHANGED
|
@@ -468,17 +468,23 @@ declare const JcfWebApi_base: HttpApi.HttpApi<"JcfWebApi", HttpApiGroup.HttpApiG
|
|
|
468
468
|
readonly endMs: Schema.Number;
|
|
469
469
|
readonly description: Schema.NullOr<Schema.String>;
|
|
470
470
|
}>;
|
|
471
|
-
}>>, Schema.toCodecJson<typeof ApiError | typeof PlanExpiredError | typeof ProposalRejectedError>, OwnerSessionAuth, never>, false> | HttpApiGroup.HttpApiGroup<"rows", HttpApiEndpoint.HttpApiEndpoint<"
|
|
472
|
-
readonly
|
|
473
|
-
readonly
|
|
471
|
+
}>>, Schema.toCodecJson<typeof ApiError | typeof PlanExpiredError | typeof ProposalRejectedError>, OwnerSessionAuth, never>, false> | HttpApiGroup.HttpApiGroup<"rows", HttpApiEndpoint.HttpApiEndpoint<"describe", "POST", "/api/rows/describe", never, never, Schema.toCodecJson<Schema.Struct<{
|
|
472
|
+
readonly planId: Schema.String;
|
|
473
|
+
readonly rowId: Schema.String;
|
|
474
|
+
}>>, never, Schema.toCodecJson<Schema.Struct<{
|
|
474
475
|
readonly planId: Schema.String;
|
|
475
476
|
readonly rowId: Schema.String;
|
|
477
|
+
readonly note: Schema.NullOr<Schema.String>;
|
|
478
|
+
}>>, Schema.toCodecJson<typeof ApiError | typeof PlanExpiredError>, OwnerSessionAuth, never> | HttpApiEndpoint.HttpApiEndpoint<"manual", "POST", "/api/rows/manual", never, never, Schema.toCodecJson<Schema.Struct<{
|
|
479
|
+
readonly day: Schema.String;
|
|
480
|
+
readonly note: Schema.optional<Schema.String>;
|
|
481
|
+
readonly seconds: Schema.Number;
|
|
476
482
|
readonly targets: Schema.optional<Schema.Struct<{
|
|
477
483
|
readonly clockify: Schema.Boolean;
|
|
478
484
|
readonly jira: Schema.Boolean;
|
|
479
485
|
}>>;
|
|
480
|
-
readonly
|
|
481
|
-
readonly ticketKey: Schema.
|
|
486
|
+
readonly startClock: Schema.optional<Schema.String>;
|
|
487
|
+
readonly ticketKey: Schema.String;
|
|
482
488
|
}>>, never, Schema.toCodecJson<Schema.Struct<{
|
|
483
489
|
readonly clockify: Schema.Union<readonly [Schema.TaggedStruct<"Written", {
|
|
484
490
|
readonly seconds: Schema.Number;
|
|
@@ -518,23 +524,17 @@ declare const JcfWebApi_base: HttpApi.HttpApi<"JcfWebApi", HttpApiGroup.HttpApiG
|
|
|
518
524
|
readonly message: Schema.String;
|
|
519
525
|
}>, Schema.TaggedStruct<"NotLoggedIn", {}>]>;
|
|
520
526
|
readonly lines: Schema.$Array<Schema.String>;
|
|
521
|
-
}>>, Schema.toCodecJson<typeof ApiError | typeof
|
|
522
|
-
readonly
|
|
523
|
-
readonly
|
|
524
|
-
}>>, never, Schema.toCodecJson<Schema.Struct<{
|
|
527
|
+
}>>, Schema.toCodecJson<typeof ApiError | typeof ProposalRejectedError>, OwnerSessionAuth, never> | HttpApiEndpoint.HttpApiEndpoint<"confirm", "POST", "/api/rows/confirm", never, never, Schema.toCodecJson<Schema.Struct<{
|
|
528
|
+
readonly blocks: Schema.optional<Schema.$Array<Schema.Number>>;
|
|
529
|
+
readonly note: Schema.optional<Schema.String>;
|
|
525
530
|
readonly planId: Schema.String;
|
|
526
531
|
readonly rowId: Schema.String;
|
|
527
|
-
readonly note: Schema.NullOr<Schema.String>;
|
|
528
|
-
}>>, Schema.toCodecJson<typeof ApiError | typeof PlanExpiredError>, OwnerSessionAuth, never> | HttpApiEndpoint.HttpApiEndpoint<"manual", "POST", "/api/rows/manual", never, never, Schema.toCodecJson<Schema.Struct<{
|
|
529
|
-
readonly day: Schema.String;
|
|
530
|
-
readonly note: Schema.optional<Schema.String>;
|
|
531
|
-
readonly seconds: Schema.Number;
|
|
532
532
|
readonly targets: Schema.optional<Schema.Struct<{
|
|
533
533
|
readonly clockify: Schema.Boolean;
|
|
534
534
|
readonly jira: Schema.Boolean;
|
|
535
535
|
}>>;
|
|
536
|
-
readonly
|
|
537
|
-
readonly ticketKey: Schema.String
|
|
536
|
+
readonly seconds: Schema.optional<Schema.Number>;
|
|
537
|
+
readonly ticketKey: Schema.optional<Schema.String>;
|
|
538
538
|
}>>, never, Schema.toCodecJson<Schema.Struct<{
|
|
539
539
|
readonly clockify: Schema.Union<readonly [Schema.TaggedStruct<"Written", {
|
|
540
540
|
readonly seconds: Schema.Number;
|
|
@@ -574,7 +574,110 @@ declare const JcfWebApi_base: HttpApi.HttpApi<"JcfWebApi", HttpApiGroup.HttpApiG
|
|
|
574
574
|
readonly message: Schema.String;
|
|
575
575
|
}>, Schema.TaggedStruct<"NotLoggedIn", {}>]>;
|
|
576
576
|
readonly lines: Schema.$Array<Schema.String>;
|
|
577
|
-
}>>, Schema.toCodecJson<typeof ApiError | typeof ProposalRejectedError>, OwnerSessionAuth, never>, false> | HttpApiGroup.HttpApiGroup<"week", HttpApiEndpoint.HttpApiEndpoint<"
|
|
577
|
+
}>>, Schema.toCodecJson<typeof ApiError | typeof PlanExpiredError | typeof ProposalRejectedError>, OwnerSessionAuth, never>, false> | HttpApiGroup.HttpApiGroup<"week", HttpApiEndpoint.HttpApiEndpoint<"saved", "GET", "/api/week/saved", never, Schema.toCodecStringTree<Schema.Struct<{
|
|
578
|
+
readonly monday: Schema.optional<Schema.String>;
|
|
579
|
+
readonly only: Schema.optional<Schema.Literals<readonly ["both", "clockify", "jira"]>>;
|
|
580
|
+
}>>, never, never, Schema.toCodecJson<Schema.Struct<{
|
|
581
|
+
readonly monday: Schema.String;
|
|
582
|
+
readonly scope: Schema.Literals<readonly ["both", "clockify", "jira"]>;
|
|
583
|
+
readonly plan: Schema.NullOr<Schema.Struct<{
|
|
584
|
+
readonly attributorAvailable: Schema.Boolean;
|
|
585
|
+
readonly attributorCalls: Schema.Number;
|
|
586
|
+
readonly days: Schema.$Array<Schema.String>;
|
|
587
|
+
readonly excludedDays: Schema.$Array<Schema.Struct<{
|
|
588
|
+
readonly day: Schema.String;
|
|
589
|
+
readonly reason: Schema.String;
|
|
590
|
+
}>>;
|
|
591
|
+
readonly monday: Schema.String;
|
|
592
|
+
readonly planId: Schema.String;
|
|
593
|
+
readonly rows: Schema.$Array<Schema.Struct<{
|
|
594
|
+
readonly clockifyDescription: Schema.NullOr<Schema.String>;
|
|
595
|
+
readonly clockifySeconds: Schema.Number;
|
|
596
|
+
readonly day: Schema.String;
|
|
597
|
+
readonly intervals: Schema.$Array<Schema.Struct<{
|
|
598
|
+
readonly entry: Schema.optionalKey<Schema.Struct<{
|
|
599
|
+
readonly revision: Schema.String;
|
|
600
|
+
readonly id: Schema.String;
|
|
601
|
+
readonly source: Schema.Literals<readonly ["jira", "clockify"]>;
|
|
602
|
+
readonly ticketKey: Schema.NullOr<Schema.String>;
|
|
603
|
+
readonly startMs: Schema.Number;
|
|
604
|
+
readonly endMs: Schema.Number;
|
|
605
|
+
readonly description: Schema.NullOr<Schema.String>;
|
|
606
|
+
}>>;
|
|
607
|
+
readonly endMs: Schema.Number;
|
|
608
|
+
readonly source: Schema.Literals<readonly ["clockify", "jira"]>;
|
|
609
|
+
readonly startMs: Schema.Number;
|
|
610
|
+
}>>;
|
|
611
|
+
readonly jiraSeconds: Schema.Number;
|
|
612
|
+
readonly proposal: Schema.optional<Schema.Struct<{
|
|
613
|
+
readonly activeSeconds: Schema.Number;
|
|
614
|
+
readonly blocks: Schema.$Array<Schema.Struct<{
|
|
615
|
+
readonly consumed: Schema.Struct<{
|
|
616
|
+
readonly clockify: Schema.Number;
|
|
617
|
+
readonly jira: Schema.Number;
|
|
618
|
+
}>;
|
|
619
|
+
readonly clockifyRefusal: Schema.optionalKey<Schema.Literal<"unlinked-overlap">>;
|
|
620
|
+
readonly endMs: Schema.Number;
|
|
621
|
+
readonly seconds: Schema.Number;
|
|
622
|
+
readonly startMs: Schema.Number;
|
|
623
|
+
readonly sourceStartMs: Schema.optional<Schema.Number>;
|
|
624
|
+
}>>;
|
|
625
|
+
readonly clockifyDelta: Schema.Number;
|
|
626
|
+
readonly confidence: Schema.NullOr<Schema.Number>;
|
|
627
|
+
readonly jiraDelta: Schema.Number;
|
|
628
|
+
readonly maxSeconds: Schema.Number;
|
|
629
|
+
readonly sessionCount: Schema.Number;
|
|
630
|
+
readonly signal: Schema.Literals<readonly ["branch", "path", "standing", "agent", "none"]>;
|
|
631
|
+
}>>;
|
|
632
|
+
readonly rowId: Schema.String;
|
|
633
|
+
readonly ticketKey: Schema.String;
|
|
634
|
+
readonly ticketTitle: Schema.NullOr<Schema.String>;
|
|
635
|
+
}>>;
|
|
636
|
+
readonly unlinkedClockify: Schema.$Array<Schema.Struct<{
|
|
637
|
+
readonly entry: Schema.optionalKey<Schema.Struct<{
|
|
638
|
+
readonly revision: Schema.String;
|
|
639
|
+
readonly id: Schema.String;
|
|
640
|
+
readonly source: Schema.Literals<readonly ["jira", "clockify"]>;
|
|
641
|
+
readonly ticketKey: Schema.NullOr<Schema.String>;
|
|
642
|
+
readonly startMs: Schema.Number;
|
|
643
|
+
readonly endMs: Schema.Number;
|
|
644
|
+
readonly description: Schema.NullOr<Schema.String>;
|
|
645
|
+
}>>;
|
|
646
|
+
readonly day: Schema.String;
|
|
647
|
+
readonly seconds: Schema.Number;
|
|
648
|
+
readonly description: Schema.NullOr<Schema.String>;
|
|
649
|
+
readonly startMs: Schema.Number;
|
|
650
|
+
readonly endMs: Schema.Number;
|
|
651
|
+
}>>;
|
|
652
|
+
readonly sessionCount: Schema.Number;
|
|
653
|
+
readonly sessionScanAvailable: Schema.optional<Schema.Boolean>;
|
|
654
|
+
readonly scope: Schema.Literals<readonly ["both", "clockify", "jira"]>;
|
|
655
|
+
readonly sessionRootCount: Schema.Number;
|
|
656
|
+
readonly notMine: Schema.$Array<Schema.Struct<{
|
|
657
|
+
readonly assignee: Schema.NullOr<Schema.String>;
|
|
658
|
+
readonly day: Schema.String;
|
|
659
|
+
readonly seconds: Schema.Number;
|
|
660
|
+
readonly signal: Schema.Literals<readonly ["branch", "path", "standing", "agent", "none"]>;
|
|
661
|
+
readonly ticketKey: Schema.String;
|
|
662
|
+
readonly ticketTitle: Schema.NullOr<Schema.String>;
|
|
663
|
+
}>>;
|
|
664
|
+
readonly ownershipChecked: Schema.Boolean;
|
|
665
|
+
readonly ownership: Schema.Literals<readonly ["assigned", "any"]>;
|
|
666
|
+
readonly unattributed: Schema.$Array<Schema.Struct<{
|
|
667
|
+
readonly cwds: Schema.$Array<Schema.String>;
|
|
668
|
+
readonly day: Schema.String;
|
|
669
|
+
readonly seconds: Schema.Number;
|
|
670
|
+
readonly sessionCount: Schema.Number;
|
|
671
|
+
}>>;
|
|
672
|
+
readonly withheld: Schema.$Array<Schema.Struct<{
|
|
673
|
+
readonly confidence: Schema.NullOr<Schema.Number>;
|
|
674
|
+
readonly day: Schema.String;
|
|
675
|
+
readonly seconds: Schema.Number;
|
|
676
|
+
readonly ticketKey: Schema.String;
|
|
677
|
+
readonly ticketTitle: Schema.NullOr<Schema.String>;
|
|
678
|
+
}>>;
|
|
679
|
+
}>>;
|
|
680
|
+
}>>, never, OwnerSessionAuth, never> | HttpApiEndpoint.HttpApiEndpoint<"read", "GET", "/api/week/", never, Schema.toCodecStringTree<Schema.Struct<{
|
|
578
681
|
readonly monday: Schema.optional<Schema.String>;
|
|
579
682
|
readonly only: Schema.optional<Schema.Literals<readonly ["both", "clockify", "jira"]>>;
|
|
580
683
|
}>>, never, never, Schema.toCodecJson<Schema.Struct<{
|
|
@@ -678,110 +781,7 @@ declare const JcfWebApi_base: HttpApi.HttpApi<"JcfWebApi", HttpApiGroup.HttpApiG
|
|
|
678
781
|
}>>, never, never, HttpApiSchema.StreamUint8Array, Schema.toCodecJson<typeof ApiError | typeof PlanExpiredError>, OwnerSessionAuth, never> | HttpApiEndpoint.HttpApiEndpoint<"recordedOnly", "GET", "/api/week/recorded-only", never, Schema.toCodecStringTree<Schema.Struct<{
|
|
679
782
|
readonly monday: Schema.optional<Schema.String>;
|
|
680
783
|
readonly only: Schema.optional<Schema.Literals<readonly ["both", "clockify", "jira"]>>;
|
|
681
|
-
}>>, never, never, HttpApiSchema.StreamUint8Array, Schema.toCodecJson<typeof ApiError | typeof PlanExpiredError>, OwnerSessionAuth, never> | HttpApiEndpoint.HttpApiEndpoint<"
|
|
682
|
-
readonly monday: Schema.optional<Schema.String>;
|
|
683
|
-
readonly only: Schema.optional<Schema.Literals<readonly ["both", "clockify", "jira"]>>;
|
|
684
|
-
}>>, never, never, Schema.toCodecJson<Schema.Struct<{
|
|
685
|
-
readonly monday: Schema.String;
|
|
686
|
-
readonly scope: Schema.Literals<readonly ["both", "clockify", "jira"]>;
|
|
687
|
-
readonly plan: Schema.NullOr<Schema.Struct<{
|
|
688
|
-
readonly attributorAvailable: Schema.Boolean;
|
|
689
|
-
readonly attributorCalls: Schema.Number;
|
|
690
|
-
readonly days: Schema.$Array<Schema.String>;
|
|
691
|
-
readonly excludedDays: Schema.$Array<Schema.Struct<{
|
|
692
|
-
readonly day: Schema.String;
|
|
693
|
-
readonly reason: Schema.String;
|
|
694
|
-
}>>;
|
|
695
|
-
readonly monday: Schema.String;
|
|
696
|
-
readonly planId: Schema.String;
|
|
697
|
-
readonly rows: Schema.$Array<Schema.Struct<{
|
|
698
|
-
readonly clockifyDescription: Schema.NullOr<Schema.String>;
|
|
699
|
-
readonly clockifySeconds: Schema.Number;
|
|
700
|
-
readonly day: Schema.String;
|
|
701
|
-
readonly intervals: Schema.$Array<Schema.Struct<{
|
|
702
|
-
readonly entry: Schema.optionalKey<Schema.Struct<{
|
|
703
|
-
readonly revision: Schema.String;
|
|
704
|
-
readonly id: Schema.String;
|
|
705
|
-
readonly source: Schema.Literals<readonly ["jira", "clockify"]>;
|
|
706
|
-
readonly ticketKey: Schema.NullOr<Schema.String>;
|
|
707
|
-
readonly startMs: Schema.Number;
|
|
708
|
-
readonly endMs: Schema.Number;
|
|
709
|
-
readonly description: Schema.NullOr<Schema.String>;
|
|
710
|
-
}>>;
|
|
711
|
-
readonly endMs: Schema.Number;
|
|
712
|
-
readonly source: Schema.Literals<readonly ["clockify", "jira"]>;
|
|
713
|
-
readonly startMs: Schema.Number;
|
|
714
|
-
}>>;
|
|
715
|
-
readonly jiraSeconds: Schema.Number;
|
|
716
|
-
readonly proposal: Schema.optional<Schema.Struct<{
|
|
717
|
-
readonly activeSeconds: Schema.Number;
|
|
718
|
-
readonly blocks: Schema.$Array<Schema.Struct<{
|
|
719
|
-
readonly consumed: Schema.Struct<{
|
|
720
|
-
readonly clockify: Schema.Number;
|
|
721
|
-
readonly jira: Schema.Number;
|
|
722
|
-
}>;
|
|
723
|
-
readonly clockifyRefusal: Schema.optionalKey<Schema.Literal<"unlinked-overlap">>;
|
|
724
|
-
readonly endMs: Schema.Number;
|
|
725
|
-
readonly seconds: Schema.Number;
|
|
726
|
-
readonly startMs: Schema.Number;
|
|
727
|
-
readonly sourceStartMs: Schema.optional<Schema.Number>;
|
|
728
|
-
}>>;
|
|
729
|
-
readonly clockifyDelta: Schema.Number;
|
|
730
|
-
readonly confidence: Schema.NullOr<Schema.Number>;
|
|
731
|
-
readonly jiraDelta: Schema.Number;
|
|
732
|
-
readonly maxSeconds: Schema.Number;
|
|
733
|
-
readonly sessionCount: Schema.Number;
|
|
734
|
-
readonly signal: Schema.Literals<readonly ["branch", "path", "standing", "agent", "none"]>;
|
|
735
|
-
}>>;
|
|
736
|
-
readonly rowId: Schema.String;
|
|
737
|
-
readonly ticketKey: Schema.String;
|
|
738
|
-
readonly ticketTitle: Schema.NullOr<Schema.String>;
|
|
739
|
-
}>>;
|
|
740
|
-
readonly unlinkedClockify: Schema.$Array<Schema.Struct<{
|
|
741
|
-
readonly entry: Schema.optionalKey<Schema.Struct<{
|
|
742
|
-
readonly revision: Schema.String;
|
|
743
|
-
readonly id: Schema.String;
|
|
744
|
-
readonly source: Schema.Literals<readonly ["jira", "clockify"]>;
|
|
745
|
-
readonly ticketKey: Schema.NullOr<Schema.String>;
|
|
746
|
-
readonly startMs: Schema.Number;
|
|
747
|
-
readonly endMs: Schema.Number;
|
|
748
|
-
readonly description: Schema.NullOr<Schema.String>;
|
|
749
|
-
}>>;
|
|
750
|
-
readonly day: Schema.String;
|
|
751
|
-
readonly seconds: Schema.Number;
|
|
752
|
-
readonly description: Schema.NullOr<Schema.String>;
|
|
753
|
-
readonly startMs: Schema.Number;
|
|
754
|
-
readonly endMs: Schema.Number;
|
|
755
|
-
}>>;
|
|
756
|
-
readonly sessionCount: Schema.Number;
|
|
757
|
-
readonly sessionScanAvailable: Schema.optional<Schema.Boolean>;
|
|
758
|
-
readonly scope: Schema.Literals<readonly ["both", "clockify", "jira"]>;
|
|
759
|
-
readonly sessionRootCount: Schema.Number;
|
|
760
|
-
readonly notMine: Schema.$Array<Schema.Struct<{
|
|
761
|
-
readonly assignee: Schema.NullOr<Schema.String>;
|
|
762
|
-
readonly day: Schema.String;
|
|
763
|
-
readonly seconds: Schema.Number;
|
|
764
|
-
readonly signal: Schema.Literals<readonly ["branch", "path", "standing", "agent", "none"]>;
|
|
765
|
-
readonly ticketKey: Schema.String;
|
|
766
|
-
readonly ticketTitle: Schema.NullOr<Schema.String>;
|
|
767
|
-
}>>;
|
|
768
|
-
readonly ownershipChecked: Schema.Boolean;
|
|
769
|
-
readonly ownership: Schema.Literals<readonly ["assigned", "any"]>;
|
|
770
|
-
readonly unattributed: Schema.$Array<Schema.Struct<{
|
|
771
|
-
readonly cwds: Schema.$Array<Schema.String>;
|
|
772
|
-
readonly day: Schema.String;
|
|
773
|
-
readonly seconds: Schema.Number;
|
|
774
|
-
readonly sessionCount: Schema.Number;
|
|
775
|
-
}>>;
|
|
776
|
-
readonly withheld: Schema.$Array<Schema.Struct<{
|
|
777
|
-
readonly confidence: Schema.NullOr<Schema.Number>;
|
|
778
|
-
readonly day: Schema.String;
|
|
779
|
-
readonly seconds: Schema.Number;
|
|
780
|
-
readonly ticketKey: Schema.String;
|
|
781
|
-
readonly ticketTitle: Schema.NullOr<Schema.String>;
|
|
782
|
-
}>>;
|
|
783
|
-
}>>;
|
|
784
|
-
}>>, never, OwnerSessionAuth, never> | HttpApiEndpoint.HttpApiEndpoint<"stream", "GET", "/api/week/stream", never, Schema.toCodecStringTree<Schema.Struct<{
|
|
784
|
+
}>>, never, never, HttpApiSchema.StreamUint8Array, Schema.toCodecJson<typeof ApiError | typeof PlanExpiredError>, OwnerSessionAuth, never> | HttpApiEndpoint.HttpApiEndpoint<"stream", "GET", "/api/week/stream", never, Schema.toCodecStringTree<Schema.Struct<{
|
|
785
785
|
readonly monday: Schema.optional<Schema.String>;
|
|
786
786
|
readonly only: Schema.optional<Schema.Literals<readonly ["both", "clockify", "jira"]>>;
|
|
787
787
|
}>>, never, never, HttpApiSchema.StreamUint8Array, Schema.toCodecJson<typeof ApiError | typeof PlanExpiredError>, OwnerSessionAuth, never>, false>>;
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
/** The same authenticated routes, bootstrap exchange and static client in production and tests. */
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
/**
|
|
5
|
-
|
|
2
|
+
import * as OwnerSession from "@knpkv/browser-pairing/owner-session";
|
|
3
|
+
import { Layer, Path } from "effect";
|
|
4
|
+
/**
|
|
5
|
+
* Serves the built client at `root`, from the same origin as the API so the session cookie applies to
|
|
6
|
+
* both. Extensionless HTML navigations fall back to `index.html`; `no-cache` makes the browser
|
|
7
|
+
* revalidate, so a rebuilt `index.html` never points at hashed assets that no longer exist.
|
|
8
|
+
*/
|
|
9
|
+
export declare const staticClient: (root: string) => Layer.Layer<never, import("effect/PlatformError").PlatformError, import("effect/FileSystem").FileSystem | import("effect/http/HttpPlatform").HttpPlatform | import("effect/http/HttpRouter").HttpRouter | Path.Path>;
|
|
10
|
+
/**
|
|
11
|
+
* The client `vite build` writes next to the compiled server. It reads host files, so give it the
|
|
12
|
+
* host's FileSystem even where the engine runs on another one.
|
|
13
|
+
*/
|
|
14
|
+
export declare const StaticRouter: Layer.Layer<never, import("effect/PlatformError").BadArgument | import("effect/PlatformError").PlatformError, import("effect/FileSystem").FileSystem | import("effect/http/HttpPlatform").HttpPlatform | import("effect/http/HttpRouter").HttpRouter | Path.Path>;
|
|
15
|
+
/** The authenticated API and the bootstrap exchange: everything that runs on the engine's services. */
|
|
16
|
+
export declare const apiApplication: Layer.Layer<never, never, import("@knpkv/jira-clockify/services/ConfigService.js").ConfigService | import("effect/Crypto").Crypto | import("effect/FileSystem").FileSystem | import("effect/http/Etag").Generator | import("effect/http/HttpPlatform").HttpPlatform | import("effect/http/HttpRouter").HttpRouter | import("@knpkv/jira-clockify/services/IssueFacts.js").IssueFacts | import("@knpkv/jira-api-client").JiraApiClient | import("@knpkv/jira-cli/JiraAuth").JiraAuth | OwnerSession.OwnerSession | Path.Path | import("@knpkv/jira-clockify/services/ReconcileService.js").ReconcileService | import("effect/http/HttpRouter").Request<"Error", import("effect/http/HttpBody").HttpBodyError> | import("@knpkv/jira-clockify/services/SavedEntries.js").SavedEntries | import("@knpkv/jira-clockify/services/SessionAttributor.js").SessionAttributor>;
|
|
6
17
|
/** Supply engine services and owner secrets; listener and platform belong to the executable. */
|
|
7
|
-
export declare const application: Layer.Layer<never, never, import("@knpkv/jira-clockify/services/ConfigService.js").ConfigService | import("effect/Crypto").Crypto | FileSystem.FileSystem | import("effect/http/Etag").Generator | import("effect/http/HttpPlatform").HttpPlatform | HttpRouter.HttpRouter | import("@knpkv/jira-clockify/services/IssueFacts.js").IssueFacts | import("@knpkv/jira-api-client").JiraApiClient | import("@knpkv/jira-cli/JiraAuth").JiraAuth |
|
|
18
|
+
export declare const application: Layer.Layer<never, never, import("@knpkv/jira-clockify/services/ConfigService.js").ConfigService | import("effect/Crypto").Crypto | import("effect/FileSystem").FileSystem | import("effect/http/Etag").Generator | import("effect/http/HttpPlatform").HttpPlatform | import("effect/http/HttpRouter").HttpRouter | import("@knpkv/jira-clockify/services/IssueFacts.js").IssueFacts | import("@knpkv/jira-api-client").JiraApiClient | import("@knpkv/jira-cli/JiraAuth").JiraAuth | OwnerSession.OwnerSession | Path.Path | import("@knpkv/jira-clockify/services/ReconcileService.js").ReconcileService | import("effect/http/HttpRouter").Request<"Error", import("effect/http/HttpBody").HttpBodyError> | import("@knpkv/jira-clockify/services/SavedEntries.js").SavedEntries | import("@knpkv/jira-clockify/services/SessionAttributor.js").SessionAttributor>;
|
|
@@ -1,62 +1,29 @@
|
|
|
1
1
|
/** The same authenticated routes, bootstrap exchange and static client in production and tests. */
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import * as OwnerSession from "@knpkv/browser-pairing/owner-session";
|
|
3
|
+
import { Effect, Layer, Path } from "effect";
|
|
4
|
+
import { HttpStaticServer } from "effect/http";
|
|
4
5
|
import { HttpApiBuilder } from "effect/http-api";
|
|
5
6
|
import { JcfWebApi } from "./Api.js";
|
|
6
7
|
import { ConfigLive, EntriesLive, RowsLive, WeekLive } from "./Handlers.js";
|
|
7
|
-
import { ownerSessionAuthLayer
|
|
8
|
+
import { ownerSessionAuthLayer } from "./OwnerSession.js";
|
|
8
9
|
import { layer as weekPlansLayer } from "./WeekPlans.js";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
export const isWithinDirectory = (path, root, candidate) => {
|
|
21
|
-
const relative = path.relative(root, candidate);
|
|
22
|
-
return relative === "" || (!path.isAbsolute(relative) && relative !== ".." &&
|
|
23
|
-
!relative.startsWith(`..${path.sep}`));
|
|
24
|
-
};
|
|
25
|
-
/** The built client, served from the same origin so the session cookie applies to both. */
|
|
26
|
-
const serveStatic = Effect.gen(function* () {
|
|
27
|
-
const request = yield* HttpServerRequest.HttpServerRequest;
|
|
28
|
-
const fileSystem = yield* FileSystem.FileSystem;
|
|
10
|
+
/**
|
|
11
|
+
* Serves the built client at `root`, from the same origin as the API so the session cookie applies to
|
|
12
|
+
* both. Extensionless HTML navigations fall back to `index.html`; `no-cache` makes the browser
|
|
13
|
+
* revalidate, so a rebuilt `index.html` never points at hashed assets that no longer exist.
|
|
14
|
+
*/
|
|
15
|
+
export const staticClient = (root) => HttpStaticServer.layer({ cacheControl: "no-cache", root, spa: true });
|
|
16
|
+
/**
|
|
17
|
+
* The client `vite build` writes next to the compiled server. It reads host files, so give it the
|
|
18
|
+
* host's FileSystem even where the engine runs on another one.
|
|
19
|
+
*/
|
|
20
|
+
export const StaticRouter = Layer.unwrap(Effect.gen(function* () {
|
|
29
21
|
const path = yield* Path.Path;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const staticDirectory = path.resolve(here, "../../dist/client");
|
|
33
|
-
const resolved = path.resolve(staticDirectory, requested === "" ? "index.html" : requested);
|
|
34
|
-
// A resolved path that escaped the directory is a traversal attempt, not a missing file.
|
|
35
|
-
if (!isWithinDirectory(path, staticDirectory, resolved)) {
|
|
36
|
-
return HttpServerResponse.text("Forbidden", { status: 403 });
|
|
37
|
-
}
|
|
38
|
-
if (yield* fileSystem.exists(resolved)) {
|
|
39
|
-
const info = yield* fileSystem.stat(resolved);
|
|
40
|
-
if (info.type === "File") {
|
|
41
|
-
return HttpServerResponse.uint8Array(yield* fileSystem.readFile(resolved), {
|
|
42
|
-
headers: { "content-type": mimeTypes.get(path.extname(resolved)) ?? "application/octet-stream" },
|
|
43
|
-
status: 200
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
const index = path.join(staticDirectory, "index.html");
|
|
48
|
-
if (yield* fileSystem.exists(index)) {
|
|
49
|
-
return HttpServerResponse.uint8Array(yield* fileSystem.readFile(index), {
|
|
50
|
-
headers: { "content-type": "text/html" },
|
|
51
|
-
status: 200
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
return HttpServerResponse.text("The client has not been built. Run: pnpm --filter @knpkv/jcf-web build", {
|
|
55
|
-
status: 404
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
const StaticRouter = HttpRouter.use((router) => router.add("GET", "/*", serveStatic));
|
|
22
|
+
return staticClient(yield* path.fromFileUrl(new URL("../../dist/client", import.meta.url)));
|
|
23
|
+
}));
|
|
59
24
|
const ApiRoutes = HttpApiBuilder.layer(JcfWebApi).pipe(Layer.provide(Layer.mergeAll(WeekLive, RowsLive, ConfigLive, EntriesLive)), Layer.provide(ownerSessionAuthLayer), Layer.provide(weekPlansLayer));
|
|
25
|
+
/** The authenticated API and the bootstrap exchange: everything that runs on the engine's services. */
|
|
26
|
+
export const apiApplication = Layer.mergeAll(ApiRoutes, OwnerSession.BootstrapRouter).pipe(Layer.orDie);
|
|
60
27
|
/** Supply engine services and owner secrets; listener and platform belong to the executable. */
|
|
61
|
-
export const application = Layer.mergeAll(
|
|
28
|
+
export const application = Layer.mergeAll(apiApplication, StaticRouter).pipe(Layer.orDie);
|
|
62
29
|
//# sourceMappingURL=HttpApplication.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HttpApplication.js","sourceRoot":"","sources":["../../src/server/HttpApplication.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,OAAO,
|
|
1
|
+
{"version":3,"file":"HttpApplication.js","sourceRoot":"","sources":["../../src/server/HttpApplication.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,OAAO,KAAK,YAAY,MAAM,sCAAsC,CAAA;AACpE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAE,KAAK,IAAI,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAExD;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAA;AAEnH;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC3D,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAA;IAC7B,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,GAAG,CAAC,mBAAmB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;AAC7F,CAAC,CAAC,CAAC,CAAA;AAEH,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,CACpD,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,EAC1E,KAAK,CAAC,OAAO,CAAC,qBAAqB,CAAC,EACpC,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,CAC9B,CAAA;AAED,uGAAuG;AACvG,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;AAEvG,gGAAgG;AAChG,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA"}
|
|
@@ -1,62 +1,17 @@
|
|
|
1
|
-
import type { CsrfToken, PairingCode, SessionToken } from "@knpkv/browser-pairing/schema";
|
|
2
|
-
import { Context, Effect, Layer, Redacted, Ref, Schema } from "effect";
|
|
3
|
-
import { HttpRouter } from "effect/http";
|
|
4
|
-
import { ForbiddenApiError, OwnerSessionAuth, UnauthorizedApiError } from "./Api.js";
|
|
5
|
-
export interface BootstrapAttemptState {
|
|
6
|
-
readonly failedAttempts: number;
|
|
7
|
-
readonly inFlight: number;
|
|
8
|
-
}
|
|
9
|
-
export interface OwnerSessionSecretsContract {
|
|
10
|
-
/** The origin this server considers itself to be. A request's Host header is never authoritative. */
|
|
11
|
-
readonly authorityOrigin: string;
|
|
12
|
-
/**
|
|
13
|
-
* The origin the browser is expected to present. Same as the authority in production; the Vite
|
|
14
|
-
* dev server when it proxies in front of it, because that is the origin the page runs on.
|
|
15
|
-
*/
|
|
16
|
-
readonly browserOrigin: string;
|
|
17
|
-
readonly bootstrapAvailable: Ref.Ref<boolean>;
|
|
18
|
-
readonly bootstrapAttemptState: Ref.Ref<BootstrapAttemptState>;
|
|
19
|
-
readonly bootstrapExpiresAtMillis: Ref.Ref<number | undefined>;
|
|
20
|
-
readonly bootstrapToken: Redacted.Redacted<PairingCode>;
|
|
21
|
-
readonly csrfToken: Redacted.Redacted<CsrfToken>;
|
|
22
|
-
readonly ownerToken: Redacted.Redacted<SessionToken>;
|
|
23
|
-
}
|
|
24
|
-
declare const OwnerSessionSecrets_base: Context.ServiceClass<OwnerSessionSecrets, "@knpkv/jcf-web/OwnerSessionSecrets", OwnerSessionSecretsContract>;
|
|
25
|
-
export declare class OwnerSessionSecrets extends OwnerSessionSecrets_base {
|
|
26
|
-
}
|
|
27
|
-
declare const UnsafeServerOriginError_base: Schema.Class<UnsafeServerOriginError, Schema.TaggedStruct<"UnsafeServerOriginError", {
|
|
28
|
-
readonly message: Schema.String;
|
|
29
|
-
readonly origin: Schema.String;
|
|
30
|
-
}>, import("effect/Cause").YieldableError>;
|
|
31
|
-
export declare class UnsafeServerOriginError extends UnsafeServerOriginError_base {
|
|
32
|
-
}
|
|
33
|
-
export declare const isLoopbackHostname: (hostname: string) => boolean;
|
|
34
|
-
export declare const ownerSessionOrigin: (hostname: string, port: number) => string;
|
|
35
|
-
export declare const requireLoopbackOrigin: (origin: string) => Effect.Effect<string, UnsafeServerOriginError, never>;
|
|
36
|
-
/** The advertised origin: the bound server, or the dev server that proxies to it. */
|
|
37
|
-
export declare const resolvePublicOrigin: (configuredOrigin: string | undefined, authorityOrigin: string) => Effect.Effect<string, UnsafeServerOriginError, never>;
|
|
38
|
-
export declare const makeOwnerSessionSecrets: (authorityOrigin: string, configuredPublicOrigin?: string | undefined) => Effect.Effect<OwnerSessionSecretsContract, import("@knpkv/browser-pairing").BrowserPairingError | UnsafeServerOriginError, import("effect/Crypto").Crypto>;
|
|
39
|
-
/** Start the bootstrap clock. Called once the server is actually listening, never before. */
|
|
40
|
-
export declare const activateOwnerSessionBootstrap: (secrets: OwnerSessionSecretsContract) => Effect.Effect<void, import("@knpkv/browser-pairing").BrowserPairingError, never>;
|
|
41
1
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
2
|
+
* jcf-web's Owner Session: the shared `@knpkv/browser-pairing/owner-session` policy, with writes.
|
|
3
|
+
*
|
|
4
|
+
* The page saves timesheet entries, so writes need the CSRF token the bootstrap exchange returns. The
|
|
5
|
+
* Vite dev server keeps its own Origin when it proxies, so the configured public origin is also the
|
|
6
|
+
* origin every browser request is checked against: the URL that gets printed cannot be advertised and
|
|
7
|
+
* then rejected.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
44
10
|
*/
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
readonly origin: string | undefined;
|
|
53
|
-
}
|
|
54
|
-
export declare const authorizeOwnerRequest: (request: OwnerRequest, secrets: OwnerSessionSecretsContract) => Effect.Effect<undefined, ForbiddenApiError | UnauthorizedApiError, never>;
|
|
55
|
-
export declare const authorizeBootstrapRequest: (request: {
|
|
56
|
-
readonly authorization: string | undefined;
|
|
57
|
-
readonly origin: string | undefined;
|
|
58
|
-
}, secrets: OwnerSessionSecretsContract) => Effect.Effect<undefined, ForbiddenApiError | UnauthorizedApiError, never>;
|
|
59
|
-
export declare const ownerSessionAuthLayer: Layer.Layer<OwnerSessionAuth, never, OwnerSessionSecrets>;
|
|
60
|
-
/** The one route outside the authenticated API: spending the printed code for a session. */
|
|
61
|
-
export declare const OwnerSessionBootstrapRouter: Layer.Layer<never, never, HttpRouter.HttpRouter | HttpRouter.Request<"Error", import("effect/http/HttpBody").HttpBodyError> | HttpRouter.Request<"Requires", OwnerSessionSecrets>>;
|
|
62
|
-
export {};
|
|
11
|
+
import type { BrowserPairingError, CredentialCookieError } from "@knpkv/browser-pairing";
|
|
12
|
+
import * as OwnerSession from "@knpkv/browser-pairing/owner-session";
|
|
13
|
+
import { type Crypto, Effect, Layer } from "effect";
|
|
14
|
+
import { OwnerSessionAuth } from "./Api.js";
|
|
15
|
+
/** Build the session for a server bound at `authorityOrigin`, advertised at `configuredPublicOrigin`. */
|
|
16
|
+
export declare const makeOwnerSession: (authorityOrigin: string, configuredPublicOrigin?: string | undefined) => Effect.Effect<OwnerSession.OwnerSessionService, BrowserPairingError | CredentialCookieError | OwnerSession.UnsafeLoopbackAddressError, Crypto.Crypto>;
|
|
17
|
+
export declare const ownerSessionAuthLayer: Layer.Layer<OwnerSessionAuth, never, OwnerSession.OwnerSession>;
|