@ref0/sdk 0.10.0 → 0.11.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/client.mjs
CHANGED
|
@@ -5423,12 +5423,15 @@ const name = ownerNamePattern.source.replace(/^\^|\$$/g, "");
|
|
|
5423
5423
|
const projectPattern = new RegExp(`^(${name})/(${name})$`);
|
|
5424
5424
|
const threadPattern = new RegExp(`^(${name})(?:/(${name}))?#([1-9][0-9]*)$`);
|
|
5425
5425
|
const repoPattern = new RegExp(`^(${name})/(${repoNamePattern.source.replace(/^\^|\$$/g, "")})$`);
|
|
5426
|
+
const pullRequestPattern = new RegExp(`${repoPattern.source.replace(/\$$/, "")}#[1-9][0-9]*$`);
|
|
5426
5427
|
/** A project, `owner/project`. */
|
|
5427
5428
|
const WrittenProject = Schema.String.check(Schema.isPattern(projectPattern)).pipe(Schema.brand("WrittenProject"));
|
|
5428
5429
|
/** A thread, `owner/project#number`, or an org thread, `owner#number`. */
|
|
5429
5430
|
const WrittenThread = Schema.String.check(Schema.isPattern(threadPattern)).pipe(Schema.brand("WrittenThread"));
|
|
5430
5431
|
/** A repo, `owner/repo`. */
|
|
5431
5432
|
const WrittenRepo = Schema.String.check(Schema.isPattern(repoPattern)).pipe(Schema.brand("WrittenRepo"));
|
|
5433
|
+
/** A pull request, `owner/repo#number`. */
|
|
5434
|
+
const WrittenPullRequest = Schema.String.check(Schema.isPattern(pullRequestPattern)).pipe(Schema.brand("WrittenPullRequest"));
|
|
5432
5435
|
/** A written project's parts, as an endpoint's path takes them. */
|
|
5433
5436
|
const projectParts = (written) => {
|
|
5434
5437
|
const [, owner = "", project = ""] = projectPattern.exec(written) ?? [];
|
|
@@ -5437,6 +5440,15 @@ const projectParts = (written) => {
|
|
|
5437
5440
|
project
|
|
5438
5441
|
};
|
|
5439
5442
|
};
|
|
5443
|
+
/** A written thread's parts, as an endpoint's path takes them: no project for an org thread. */
|
|
5444
|
+
const threadParts = (written) => {
|
|
5445
|
+
const [, owner = "", project, number = ""] = threadPattern.exec(written) ?? [];
|
|
5446
|
+
return {
|
|
5447
|
+
owner,
|
|
5448
|
+
project,
|
|
5449
|
+
number
|
|
5450
|
+
};
|
|
5451
|
+
};
|
|
5440
5452
|
//#endregion
|
|
5441
5453
|
//#region ../contracts/src/mention-views.ts
|
|
5442
5454
|
/**
|
|
@@ -6676,594 +6688,227 @@ Schema.Union([Schema.Struct({ found: Schema.Literal(false) }), Schema.Struct({
|
|
|
6676
6688
|
attachGrant: Schema.optionalKey(EventId)
|
|
6677
6689
|
})]);
|
|
6678
6690
|
//#endregion
|
|
6679
|
-
//#region ../contracts/src/
|
|
6691
|
+
//#region ../contracts/src/plan-events.ts
|
|
6680
6692
|
/**
|
|
6681
|
-
*
|
|
6682
|
-
*
|
|
6683
|
-
* that endpoint encodes it. ref0 decodes each part by the endpoint's own `Schema` before it
|
|
6684
|
-
* keeps or shows anything, so a command is exactly what the endpoint would take.
|
|
6693
|
+
* A plan's events, in its thread's project's log, written by the Project DO. A version's
|
|
6694
|
+
* state is folded from these and its thread's, never recorded on its own.
|
|
6685
6695
|
*/
|
|
6686
6696
|
/**
|
|
6687
|
-
*
|
|
6688
|
-
*
|
|
6697
|
+
* A new version, as a draft. Its content never changes after this. Its reason, when given, says
|
|
6698
|
+
* why it was written; it's beside the plan, never in it, so it's no part of the content hash.
|
|
6689
6699
|
*/
|
|
6690
|
-
const
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
});
|
|
6698
|
-
/** A command ref0 won't ask anyone about: not an endpoint's request, or not one an approval runs. */
|
|
6699
|
-
var CommandRefused = class extends Schema.TaggedError()("CommandRefused", { nextStep: Schema.String }, { httpApiStatus: 400 }) {};
|
|
6700
|
-
/** A terminal asking: its command, and the hash of the secret it collects the result with. */
|
|
6701
|
-
const StartApproval = Schema.Struct({
|
|
6702
|
-
command: ApprovalCommand,
|
|
6703
|
-
secretHash: SecretHash
|
|
6704
|
-
});
|
|
6705
|
-
/** A terminal's approval, started: what to show its person, and until when. */
|
|
6706
|
-
const ApprovalStarted = Schema.Struct({
|
|
6707
|
-
approval: ApprovalId,
|
|
6708
|
-
code: ApprovalCode,
|
|
6709
|
-
expiresAt: Timestamp
|
|
6710
|
-
});
|
|
6700
|
+
const PlanWritten = eventKind("plan.written", Schema.Struct({
|
|
6701
|
+
thread: ThreadId,
|
|
6702
|
+
version: PlanVersion,
|
|
6703
|
+
plan: PlanRecord,
|
|
6704
|
+
contentHash: PlanContentHash,
|
|
6705
|
+
reason: Schema.optionalKey(TextId)
|
|
6706
|
+
}));
|
|
6711
6707
|
/**
|
|
6712
|
-
*
|
|
6713
|
-
*
|
|
6714
|
-
*
|
|
6708
|
+
* The version is put to approval: each repo it names is asked to answer for it, and ref0 says yes
|
|
6709
|
+
* once they have or their time runs out. Any earlier draft or proposed version is
|
|
6710
|
+
* superseded.
|
|
6715
6711
|
*/
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
const
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
kind: Schema.Literal("agent"),
|
|
6725
|
-
agent: AgentId,
|
|
6726
|
-
handle: AgentHandle,
|
|
6727
|
-
session: SessionId,
|
|
6728
|
-
/** The attachment its credential was made under, for a person's agent in an organization. */
|
|
6729
|
-
attachment: Schema.optionalKey(CredentialRef)
|
|
6712
|
+
const PlanProposed = eventKind("plan.proposed", Schema.Struct({
|
|
6713
|
+
thread: ThreadId,
|
|
6714
|
+
version: PlanVersion
|
|
6715
|
+
}));
|
|
6716
|
+
/** Who said yes: ref0's plans part, once every repo answered or its time ran out. */
|
|
6717
|
+
const PlanAcceptedBy = Schema.Struct({
|
|
6718
|
+
kind: Schema.Literal("answered"),
|
|
6719
|
+
part: Ref0Part
|
|
6730
6720
|
});
|
|
6731
|
-
/**
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
const ApprovalAsker = Schema.Union([
|
|
6736
|
-
terminalAsker,
|
|
6737
|
-
pageAsker,
|
|
6738
|
-
Schema.Struct({
|
|
6739
|
-
kind: Schema.Literal("machine"),
|
|
6740
|
-
machine: MachineId,
|
|
6741
|
-
machineName: MachineName,
|
|
6742
|
-
askedFrom: Schema.optionalKey(Schema.String)
|
|
6743
|
-
}),
|
|
6744
|
-
agentAsker
|
|
6745
|
-
]);
|
|
6746
|
-
/**
|
|
6747
|
-
* Who asked, as the person reads a request before they answer: a terminal, a page or an agent.
|
|
6748
|
-
* A machine's request is read as an `AttachmentRequestView`, never as a command.
|
|
6749
|
-
*/
|
|
6750
|
-
const ApprovalViewAsker = Schema.Union([
|
|
6751
|
-
terminalAsker,
|
|
6752
|
-
pageAsker,
|
|
6753
|
-
agentAsker
|
|
6754
|
-
]);
|
|
6755
|
-
/** A request, as the person reads it before they answer. */
|
|
6756
|
-
const ApprovalView = Schema.Struct({
|
|
6757
|
-
approval: ApprovalId,
|
|
6758
|
-
/** The command as its CLI line. */
|
|
6759
|
-
says: Schema.String,
|
|
6760
|
-
/** Everything the command carries, each named, in order: nothing it would run is left out. */
|
|
6761
|
-
fields: Schema.Array(Schema.Struct({
|
|
6762
|
-
name: Schema.String,
|
|
6763
|
-
value: Schema.String,
|
|
6764
|
-
part: Schema.Literals([
|
|
6765
|
-
"path",
|
|
6766
|
-
"query",
|
|
6767
|
-
"payload"
|
|
6768
|
-
])
|
|
6769
|
-
})),
|
|
6770
|
-
command: ApprovalCommand,
|
|
6771
|
-
asker: ApprovalViewAsker,
|
|
6772
|
-
askedFrom: Schema.optionalKey(Schema.String),
|
|
6773
|
-
askedAt: Timestamp,
|
|
6774
|
-
expiresAt: Timestamp,
|
|
6775
|
-
/**
|
|
6776
|
-
* An agent's ask: the kind of action its answer may set agents' permission for, and whether a
|
|
6777
|
-
* yes may let agents take it without asking. A no with the passkey may always stop them asking.
|
|
6778
|
-
*/
|
|
6779
|
-
agentPermission: Schema.optionalKey(Schema.Struct({
|
|
6780
|
-
action: ScopeAction,
|
|
6781
|
-
mayAllow: Schema.Boolean
|
|
6782
|
-
})),
|
|
6783
|
-
/**
|
|
6784
|
-
* What the command acts on, drawn as ref0 resolves it for the person reading, where its
|
|
6785
|
-
* endpoint names a preview. Without one the page can draw, it offers only no.
|
|
6786
|
-
*/
|
|
6787
|
-
preview: Schema.optionalKey(ApprovalPreview)
|
|
6721
|
+
/** A child thread, by the plan entry that made it. */
|
|
6722
|
+
const PlanChildThread = Schema.Struct({
|
|
6723
|
+
entry: PlanEntryKey,
|
|
6724
|
+
thread: ThreadId
|
|
6788
6725
|
});
|
|
6789
|
-
|
|
6790
|
-
const StatementHash = Schema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/));
|
|
6726
|
+
const ChildThreads = Schema.Array(PlanChildThread).check(Schema.isMaxLength(50));
|
|
6791
6727
|
/**
|
|
6792
|
-
*
|
|
6793
|
-
*
|
|
6794
|
-
* the check run its statement is over.
|
|
6728
|
+
* The version is accepted, and the one accepted before it superseded. Each child is named only
|
|
6729
|
+
* once its owner has registered it.
|
|
6795
6730
|
*/
|
|
6796
|
-
const
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
version:
|
|
6805
|
-
|
|
6806
|
-
|
|
6731
|
+
const PlanAccepted = eventKind("plan.accepted", Schema.Struct({
|
|
6732
|
+
thread: ThreadId,
|
|
6733
|
+
version: PlanVersion,
|
|
6734
|
+
by: PlanAcceptedBy,
|
|
6735
|
+
/** The version accepted before this one. */
|
|
6736
|
+
supersedes: Schema.optionalKey(PlanVersion),
|
|
6737
|
+
/** Children made now, each starting in planning. */
|
|
6738
|
+
started: ChildThreads,
|
|
6739
|
+
/** Entries an earlier version dropped and this one adds back: the same child, reopened if it was closed. */
|
|
6740
|
+
rejoined: ChildThreads,
|
|
6741
|
+
/** Children no longer part of the plan, so it stops waiting on them. Closing one is its own event. */
|
|
6742
|
+
dropped: ChildThreads
|
|
6743
|
+
}));
|
|
6744
|
+
//#endregion
|
|
6745
|
+
//#region ../contracts/src/plan-calls.ts
|
|
6807
6746
|
/**
|
|
6808
|
-
*
|
|
6809
|
-
*
|
|
6810
|
-
*
|
|
6811
|
-
* whom it asks, the run's accountable person, or for a gate the person behind its run, a person by
|
|
6812
|
-
* name, or a permission's holders; and until when.
|
|
6747
|
+
* Plans and decisions: what the Worker asks a thread's Project DO, once `Authorize` has said
|
|
6748
|
+
* who's acting. A plan is written with its words; the Project DO stores each as a text and
|
|
6749
|
+
* records the version with their IDs.
|
|
6813
6750
|
*/
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
statement: WorkflowText,
|
|
6817
|
-
hash: StatementHash,
|
|
6818
|
-
asker: StatementAsker,
|
|
6819
|
-
home: Schema.String,
|
|
6820
|
-
from: Schema.Union([Schema.Literals(["accountable", "person"]), Schema.Struct({ permission: RepoPermissionName })]),
|
|
6821
|
-
askedAt: Timestamp,
|
|
6822
|
-
expiresAt: Timestamp
|
|
6823
|
-
});
|
|
6751
|
+
/** A plan's free text: one of its outcomes, or an answer's reason. */
|
|
6752
|
+
const PlanText = Schema.String.check(Schema.isBetweenLength(1, 2048));
|
|
6824
6753
|
/**
|
|
6825
|
-
*
|
|
6826
|
-
*
|
|
6827
|
-
* again without its code.
|
|
6754
|
+
* How a plan does its work, in system terms, for people: about a page. A revision replaces it,
|
|
6755
|
+
* with a reason; no one appends to it.
|
|
6828
6756
|
*/
|
|
6829
|
-
const
|
|
6830
|
-
approvals: Schema.Array(ApprovalView),
|
|
6831
|
-
statements: Schema.Array(StatementView),
|
|
6832
|
-
requests: Schema.Array(AttachmentRequestView)
|
|
6833
|
-
});
|
|
6834
|
-
/** Finding a terminal's request by the code it showed. */
|
|
6835
|
-
const FindApproval = Schema.Union([Schema.Struct({ code: TypedApprovalCode }), Schema.Struct({ link: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{22}$/)) })]);
|
|
6757
|
+
const Approach = Schema.String.check(Schema.isBetweenLength(1, 6e3));
|
|
6836
6758
|
/**
|
|
6837
|
-
*
|
|
6838
|
-
*
|
|
6839
|
-
* request needs its answerer, and the agent it chooses to connect, before a yes has options.
|
|
6759
|
+
* A child as written. On a top-level org thread's plan, `project` names one of its owner's
|
|
6760
|
+
* projects to start it in, as that project's thread; left out, it's in its parent's scope.
|
|
6840
6761
|
*/
|
|
6841
|
-
const
|
|
6842
|
-
|
|
6843
|
-
|
|
6762
|
+
const PlanChildInput = Schema.Struct({
|
|
6763
|
+
entry: PlanEntryKey,
|
|
6764
|
+
title: Title,
|
|
6765
|
+
outcome: Outcome,
|
|
6766
|
+
stackedOn: Schema.optionalKey(PlanEntryKey),
|
|
6767
|
+
required: Schema.Boolean,
|
|
6768
|
+
project: Schema.optionalKey(ProjectName)
|
|
6844
6769
|
});
|
|
6845
6770
|
/**
|
|
6846
|
-
*
|
|
6847
|
-
*
|
|
6848
|
-
* it without asking; no, and stop agents asking, with the passkey too.
|
|
6771
|
+
* A plan as written: `PlanRecord`'s shape, with its words in place of text IDs. Its repos are up
|
|
6772
|
+
* to 20 of the project's, by name; a parent whose work is all in its children names none.
|
|
6849
6773
|
*/
|
|
6850
|
-
const
|
|
6851
|
-
Schema.
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
/** The preview the page drew, where the command's endpoint names one. */
|
|
6857
|
-
preview: Schema.optionalKey(PreviewEcho),
|
|
6858
|
-
/** The statement the page showed, by its hash, for a workflow run's or a gate's passkey request. */
|
|
6859
|
-
statement: Schema.optionalKey(Schema.Struct({ hash: StatementHash }))
|
|
6860
|
-
}),
|
|
6861
|
-
Schema.Struct({
|
|
6862
|
-
answer: Schema.Literal("no"),
|
|
6863
|
-
permission: Schema.Literal("deny"),
|
|
6864
|
-
assertion: PasskeyAsserted,
|
|
6865
|
-
code: Schema.optionalKey(TypedApprovalCode)
|
|
6866
|
-
}),
|
|
6867
|
-
Schema.Struct({
|
|
6868
|
-
answer: Schema.Literal("no"),
|
|
6869
|
-
code: Schema.optionalKey(TypedApprovalCode)
|
|
6870
|
-
})
|
|
6871
|
-
]);
|
|
6774
|
+
const PlanInput = Schema.Struct({
|
|
6775
|
+
approach: Schema.optionalKey(Approach),
|
|
6776
|
+
repos: Schema.Array(RepoName).check(Schema.isMaxLength(20)),
|
|
6777
|
+
outcomes: Schema.Array(PlanText).check(Schema.isBetweenLength(1, 50)),
|
|
6778
|
+
children: Schema.Array(PlanChildInput).check(Schema.isMaxLength(50))
|
|
6779
|
+
}).check(Schema.makeFilter((plan) => planProblem(plan) ?? true));
|
|
6872
6780
|
/**
|
|
6873
|
-
*
|
|
6874
|
-
*
|
|
6875
|
-
*
|
|
6876
|
-
*
|
|
6781
|
+
* A project a plan's child names, as the Worker found it in the plan's owner before it asked the
|
|
6782
|
+
* scope: its ID, and whether the writer can see it; or, with no `project`, that the owner has
|
|
6783
|
+
* none by that name. The Worker refuses nothing for it, since only the scope knows which entries
|
|
6784
|
+
* a version keeps.
|
|
6877
6785
|
*/
|
|
6878
|
-
const
|
|
6879
|
-
|
|
6880
|
-
|
|
6786
|
+
const NamedProject = Schema.Struct({
|
|
6787
|
+
name: ProjectName,
|
|
6788
|
+
project: Schema.optionalKey(ProjectId),
|
|
6789
|
+
seen: Schema.Boolean
|
|
6881
6790
|
});
|
|
6882
|
-
/**
|
|
6883
|
-
* A ran command whose answer its endpoint's schemas no longer read, such as one kept from
|
|
6884
|
-
* before they changed: it ran, and what it came to can't be said.
|
|
6885
|
-
*/
|
|
6886
|
-
var ResultUnreadable = class extends Schema.TaggedError()("ResultUnreadable", { nextStep: Schema.String }, { httpApiStatus: 500 }) {};
|
|
6887
|
-
/**
|
|
6888
|
-
* Where a request stands, for whoever asked: still waiting; approved, and running as soon as
|
|
6889
|
-
* ref0 can; refused; expired; or what it ran to, with the endpoint it ran, whose schemas read it.
|
|
6890
|
-
*/
|
|
6891
|
-
const ApprovalState = Schema.Union([
|
|
6892
|
-
Schema.Struct({
|
|
6893
|
-
state: Schema.Literal("waiting"),
|
|
6894
|
-
expiresAt: Timestamp
|
|
6895
|
-
}),
|
|
6896
|
-
Schema.Struct({
|
|
6897
|
-
state: Schema.Literal("approved"),
|
|
6898
|
-
/** A machine's answering browser may forget its saved answer once the terminal kept it. */
|
|
6899
|
-
collected: Schema.optionalKey(Schema.Literal(true))
|
|
6900
|
-
}),
|
|
6901
|
-
Schema.Struct({ state: Schema.Literal("refused") }),
|
|
6902
|
-
Schema.Struct({ state: Schema.Literal("expired") }),
|
|
6903
|
-
Schema.Struct({
|
|
6904
|
-
state: Schema.Literal("ran"),
|
|
6905
|
-
endpoint: CommandEndpoint,
|
|
6906
|
-
...Ran.fields
|
|
6907
|
-
})
|
|
6908
|
-
]);
|
|
6909
|
-
/** Only the answering browser receives a machine's answer code; state reads never carry it. */
|
|
6910
|
-
const ApprovalAnswer = Schema.Union([
|
|
6911
|
-
Schema.Struct({
|
|
6912
|
-
...ApprovalState.members[1].fields,
|
|
6913
|
-
answerCode: ApprovalCode
|
|
6914
|
-
}),
|
|
6915
|
-
Schema.Struct({
|
|
6916
|
-
...ApprovalState.members[4].fields,
|
|
6917
|
-
answerCode: ApprovalCode
|
|
6918
|
-
}),
|
|
6919
|
-
ApprovalState
|
|
6920
|
-
]);
|
|
6921
|
-
/** A request that isn't there, or isn't the caller's to see, answers the same. */
|
|
6922
|
-
var ApprovalNotFound = class extends Schema.TaggedError()("ApprovalNotFound", { nextStep: Schema.String }, { httpApiStatus: 404 }) {};
|
|
6923
|
-
/** Too many asked, or too many codes typed, from here in the last hour. */
|
|
6924
|
-
var SlowDown = class extends Schema.TaggedError()("SlowDown", { nextStep: Schema.String }, { httpApiStatus: 429 }) {};
|
|
6925
|
-
/** A command's hash: the SHA-256 of its canonical JSON, as lowercase hex. */
|
|
6926
|
-
const CommandHash = Schema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/));
|
|
6927
6791
|
Schema.Struct({
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
generation: Generation,
|
|
6937
|
-
/** When the request expires, in epoch milliseconds. */
|
|
6938
|
-
deadline: Schema.Int,
|
|
6939
|
-
challenge: Schema.String,
|
|
6940
|
-
/** A machine answer retries only from its answering session, with this key. */
|
|
6941
|
-
answerKey: Schema.optionalKey(RequestId),
|
|
6942
|
-
/** An agent's ask: the credential it asked with, checked again before the answer counts. */
|
|
6943
|
-
asking: Schema.optionalKey(TokenId),
|
|
6944
|
-
/** The kind of action the person, answering, let agents take without asking from now on. */
|
|
6945
|
-
allow: Schema.optionalKey(ScopeAction)
|
|
6792
|
+
...commandFields,
|
|
6793
|
+
project: ProjectId,
|
|
6794
|
+
ownerName: OwnerName,
|
|
6795
|
+
number: ThreadNumber,
|
|
6796
|
+
plan: PlanInput,
|
|
6797
|
+
projects: Schema.Array(NamedProject).check(Schema.isMaxLength(50)),
|
|
6798
|
+
reason: Schema.optionalKey(Reason),
|
|
6799
|
+
propose: Schema.Boolean
|
|
6946
6800
|
});
|
|
6947
6801
|
Schema.Struct({
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6802
|
+
...commandFields,
|
|
6803
|
+
ownerName: OwnerName,
|
|
6804
|
+
project: ProjectId,
|
|
6805
|
+
number: ThreadNumber,
|
|
6806
|
+
version: PlanVersion
|
|
6807
|
+
});
|
|
6808
|
+
/** A decision as it stands: what it asks, who decides, the answers so far, and how it closed. */
|
|
6809
|
+
const DecisionView = Schema.Struct({
|
|
6810
|
+
decision: DecisionId,
|
|
6811
|
+
kind: DecisionKind,
|
|
6812
|
+
subject: DecisionSubject,
|
|
6813
|
+
question: Schema.optionalKey(TextId),
|
|
6814
|
+
options: Schema.Array(AnswerOption),
|
|
6815
|
+
lean: Schema.optionalKey(AnswerKey),
|
|
6816
|
+
deciders: Schema.Array(Decider),
|
|
6817
|
+
deadline: Schema.optionalKey(Schema.DateTimeUtcFromMillis),
|
|
6818
|
+
state: Schema.Literals(["open", "closed"]),
|
|
6819
|
+
answers: Schema.Array(Schema.Struct({
|
|
6820
|
+
decider: DeciderRef,
|
|
6821
|
+
answer: AnswerKey,
|
|
6822
|
+
reason: Schema.optionalKey(TextId),
|
|
6823
|
+
at: Schema.DateTimeUtcFromMillis
|
|
6824
|
+
})),
|
|
6825
|
+
result: Schema.optionalKey(AnswerKey),
|
|
6826
|
+
closedWhy: Schema.optionalKey(DecisionClosedWhy)
|
|
6952
6827
|
});
|
|
6953
|
-
Schema.Union([Schema.Struct({ denied: Schema.Literal(true) }), Schema.Struct({
|
|
6954
|
-
denied: Schema.Literal(false),
|
|
6955
|
-
reason: Schema.Literals(["generation moved", "not set up"])
|
|
6956
|
-
})]);
|
|
6957
|
-
Schema.Union([Schema.Struct({
|
|
6958
|
-
admitted: Schema.Literal(true),
|
|
6959
|
-
admittedAt: Schema.Int,
|
|
6960
|
-
answerCode: Schema.optionalKey(ApprovalCode)
|
|
6961
|
-
}), Schema.Struct({
|
|
6962
|
-
admitted: Schema.Literal(false),
|
|
6963
|
-
reason: Schema.Literals([
|
|
6964
|
-
"expired",
|
|
6965
|
-
"generation moved",
|
|
6966
|
-
"challenge used",
|
|
6967
|
-
"not set up",
|
|
6968
|
-
"asker gone"
|
|
6969
|
-
])
|
|
6970
|
-
})]);
|
|
6971
|
-
Schema.Union([Schema.Struct({ found: Schema.Literal(false) }), Schema.Struct({
|
|
6972
|
-
found: Schema.Literal(true),
|
|
6973
|
-
endpoint: CommandEndpoint,
|
|
6974
|
-
command: Schema.String,
|
|
6975
|
-
commandHash: CommandHash,
|
|
6976
|
-
generation: Generation,
|
|
6977
|
-
generationNow: Generation,
|
|
6978
|
-
/** The `approval.answered` its admission recorded in the person's log. */
|
|
6979
|
-
answeredEvent: EventId,
|
|
6980
|
-
/** Who asked, as that `approval.answered` says. */
|
|
6981
|
-
asker: ApprovalAsker,
|
|
6982
|
-
/** What running it came to, once it ran, as `KeptRan` keeps it. */
|
|
6983
|
-
result: Schema.optionalKey(Schema.String)
|
|
6984
|
-
})]);
|
|
6985
6828
|
/**
|
|
6986
|
-
*
|
|
6987
|
-
*
|
|
6988
|
-
*
|
|
6829
|
+
* Where a decision is, as people write it: its thread, `pip/default#3`, or an org thread's,
|
|
6830
|
+
* `acme#7`; and a gate's pull request, `pip/notes#1`. Its Project DO writes them as it answers,
|
|
6831
|
+
* from its own threads and repos and the owner's name the Worker gives it, so each reads as it's
|
|
6832
|
+
* called now.
|
|
6989
6833
|
*/
|
|
6990
|
-
const
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
result: Schema.String
|
|
6834
|
+
const DecisionNames = Schema.Struct({
|
|
6835
|
+
thread: WrittenThread,
|
|
6836
|
+
pullRequest: Schema.optionalKey(WrittenPullRequest)
|
|
6994
6837
|
});
|
|
6995
|
-
|
|
6996
|
-
Schema.Struct({
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
Schema.Struct({
|
|
7000
|
-
person: PersonId,
|
|
7001
|
-
approval: ApprovalId
|
|
6838
|
+
/** A decision as `/v1` answers it: as it stands, and where it is, in words. */
|
|
6839
|
+
const NamedDecision = Schema.Struct({
|
|
6840
|
+
...DecisionView.fields,
|
|
6841
|
+
names: DecisionNames
|
|
7002
6842
|
});
|
|
7003
|
-
//#endregion
|
|
7004
|
-
//#region ../contracts/src/browser-sessions.ts
|
|
7005
6843
|
/**
|
|
7006
|
-
* A
|
|
7007
|
-
*
|
|
7008
|
-
* only the token's SHA-256.
|
|
6844
|
+
* A version as it stands: its content, its state, and, once proposed, where its approval is: its
|
|
6845
|
+
* repos still being checked, or who accepted it.
|
|
7009
6846
|
*/
|
|
7010
|
-
const
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
6847
|
+
const PlanVersionView = Schema.Struct({
|
|
6848
|
+
thread: ThreadId,
|
|
6849
|
+
number: ThreadNumber,
|
|
6850
|
+
version: PlanVersion,
|
|
6851
|
+
state: PlanState,
|
|
6852
|
+
contentHash: PlanContentHash,
|
|
6853
|
+
plan: PlanView,
|
|
6854
|
+
/** Why it was written, when its writer said: never part of its content. */
|
|
6855
|
+
reason: Schema.optionalKey(TextId),
|
|
6856
|
+
writtenBy: ActorRef,
|
|
6857
|
+
writtenAt: Schema.DateTimeUtcFromMillis,
|
|
6858
|
+
/** Proposed, and its repos haven't all answered yet: it isn't accepted yet. */
|
|
6859
|
+
checking: Schema.Boolean,
|
|
6860
|
+
/**
|
|
6861
|
+
* What its check found when it ended, every repo answered or their time run out: the repos
|
|
6862
|
+
* that never answered. None for a draft, while it's being checked, or when a newer version or
|
|
6863
|
+
* the thread closing ended the check first.
|
|
6864
|
+
*/
|
|
6865
|
+
check: Schema.optionalKey(PlanCheck),
|
|
6866
|
+
/**
|
|
6867
|
+
* Accepted, and waiting to be recorded: on its new `children` registering, or on a merge under
|
|
6868
|
+
* the thread's current revision `publishing`.
|
|
6869
|
+
*/
|
|
6870
|
+
accepting: Schema.optionalKey(Schema.Literals(["children", "publishing"])),
|
|
6871
|
+
acceptedBy: Schema.optionalKey(PlanAcceptedBy)
|
|
7015
6872
|
});
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
})
|
|
7032
|
-
/**
|
|
7033
|
-
* A browser session renewed: its expiry, in its person's Owner DO and in the directory, and on its cookie.
|
|
7034
|
-
* Renewed at most once a day, so one asked sooner answers its expiry unchanged.
|
|
7035
|
-
*/
|
|
7036
|
-
const SessionRenewed = Schema.Struct({ expiresAt: Schema.DateTimeUtcFromMillis });
|
|
6873
|
+
/** A plan's free text refused before anything was stored, saying which. */
|
|
6874
|
+
var PlanTextRefused = class extends Schema.TaggedError()("PlanTextRefused", {
|
|
6875
|
+
/** Where it is in the plan, such as `outcomes[3]`. */
|
|
6876
|
+
where: Schema.String,
|
|
6877
|
+
problem: Schema.Literals([
|
|
6878
|
+
"empty",
|
|
6879
|
+
"too long",
|
|
6880
|
+
"looks like a secret"
|
|
6881
|
+
]),
|
|
6882
|
+
nextStep: Schema.String
|
|
6883
|
+
}, { httpApiStatus: 422 }) {};
|
|
6884
|
+
/** A plan names a repo this project doesn't hold. */
|
|
6885
|
+
var PlanRepoNotFound = class extends Schema.TaggedError()("PlanRepoNotFound", {
|
|
6886
|
+
repo: RepoName,
|
|
6887
|
+
nextStep: Schema.String
|
|
6888
|
+
}, { httpApiStatus: 422 }) {};
|
|
7037
6889
|
/**
|
|
7038
|
-
*
|
|
7039
|
-
*
|
|
6890
|
+
* A plan names its scope's own repo, made just now, before the scope holds it. Nothing was kept
|
|
6891
|
+
* under the request's delivery ID, so the same request is written once it does.
|
|
7040
6892
|
*/
|
|
7041
|
-
|
|
7042
|
-
|
|
6893
|
+
var OwnRepoNotReady = class extends Schema.TaggedError()("OwnRepoNotReady", {
|
|
6894
|
+
repo: RepoName,
|
|
6895
|
+
nextStep: Schema.String
|
|
6896
|
+
}, { httpApiStatus: 503 }) {};
|
|
7043
6897
|
/**
|
|
7044
|
-
*
|
|
7045
|
-
*
|
|
6898
|
+
* A child entry this plan can't have: a project named on a project thread's plan or a nested org
|
|
6899
|
+
* thread's, a project that isn't there or the writer can't see, one where its proposer may not
|
|
6900
|
+
* start threads, an entry moved to another project, or a stack across scopes. A project that
|
|
6901
|
+
* isn't there and one the writer can't see are refused alike, as `ProjectNotFound` is.
|
|
7046
6902
|
*/
|
|
7047
|
-
|
|
6903
|
+
var PlanChildRefused = class extends Schema.TaggedError()("PlanChildRefused", { nextStep: Schema.String }, { httpApiStatus: 422 }) {};
|
|
6904
|
+
var PlanVersionNotFound = class extends Schema.TaggedError()("PlanVersionNotFound", {
|
|
6905
|
+
number: ThreadNumber,
|
|
6906
|
+
version: PlanVersion,
|
|
6907
|
+
nextStep: Schema.String
|
|
6908
|
+
}, { httpApiStatus: 404 }) {};
|
|
7048
6909
|
/**
|
|
7049
|
-
*
|
|
7050
|
-
*
|
|
7051
|
-
* serves.
|
|
7052
|
-
*/
|
|
7053
|
-
const StartSignIn = Schema.Struct({
|
|
7054
|
-
provider: Schema.Literal("github"),
|
|
7055
|
-
callbackURL: SignInDestination,
|
|
7056
|
-
errorCallbackURL: SignInDestination
|
|
7057
|
-
});
|
|
7058
|
-
/** The name a naming person chose for their owner. */
|
|
7059
|
-
const NameOwner = Schema.Struct({ name: OwnerName });
|
|
7060
|
-
//#endregion
|
|
7061
|
-
//#region ../contracts/src/plan-events.ts
|
|
7062
|
-
/**
|
|
7063
|
-
* A plan's events, in its thread's project's log, written by the Project DO. A version's
|
|
7064
|
-
* state is folded from these and its thread's, never recorded on its own.
|
|
7065
|
-
*/
|
|
7066
|
-
/**
|
|
7067
|
-
* A new version, as a draft. Its content never changes after this. Its reason, when given, says
|
|
7068
|
-
* why it was written; it's beside the plan, never in it, so it's no part of the content hash.
|
|
7069
|
-
*/
|
|
7070
|
-
const PlanWritten = eventKind("plan.written", Schema.Struct({
|
|
7071
|
-
thread: ThreadId,
|
|
7072
|
-
version: PlanVersion,
|
|
7073
|
-
plan: PlanRecord,
|
|
7074
|
-
contentHash: PlanContentHash,
|
|
7075
|
-
reason: Schema.optionalKey(TextId)
|
|
7076
|
-
}));
|
|
7077
|
-
/**
|
|
7078
|
-
* The version is put to approval: each repo it names is asked to answer for it, and ref0 says yes
|
|
7079
|
-
* once they have or their time runs out. Any earlier draft or proposed version is
|
|
7080
|
-
* superseded.
|
|
7081
|
-
*/
|
|
7082
|
-
const PlanProposed = eventKind("plan.proposed", Schema.Struct({
|
|
7083
|
-
thread: ThreadId,
|
|
7084
|
-
version: PlanVersion
|
|
7085
|
-
}));
|
|
7086
|
-
/** Who said yes: ref0's plans part, once every repo answered or its time ran out. */
|
|
7087
|
-
const PlanAcceptedBy = Schema.Struct({
|
|
7088
|
-
kind: Schema.Literal("answered"),
|
|
7089
|
-
part: Ref0Part
|
|
7090
|
-
});
|
|
7091
|
-
/** A child thread, by the plan entry that made it. */
|
|
7092
|
-
const PlanChildThread = Schema.Struct({
|
|
7093
|
-
entry: PlanEntryKey,
|
|
7094
|
-
thread: ThreadId
|
|
7095
|
-
});
|
|
7096
|
-
const ChildThreads = Schema.Array(PlanChildThread).check(Schema.isMaxLength(50));
|
|
7097
|
-
/**
|
|
7098
|
-
* The version is accepted, and the one accepted before it superseded. Each child is named only
|
|
7099
|
-
* once its owner has registered it.
|
|
7100
|
-
*/
|
|
7101
|
-
const PlanAccepted = eventKind("plan.accepted", Schema.Struct({
|
|
7102
|
-
thread: ThreadId,
|
|
7103
|
-
version: PlanVersion,
|
|
7104
|
-
by: PlanAcceptedBy,
|
|
7105
|
-
/** The version accepted before this one. */
|
|
7106
|
-
supersedes: Schema.optionalKey(PlanVersion),
|
|
7107
|
-
/** Children made now, each starting in planning. */
|
|
7108
|
-
started: ChildThreads,
|
|
7109
|
-
/** Entries an earlier version dropped and this one adds back: the same child, reopened if it was closed. */
|
|
7110
|
-
rejoined: ChildThreads,
|
|
7111
|
-
/** Children no longer part of the plan, so it stops waiting on them. Closing one is its own event. */
|
|
7112
|
-
dropped: ChildThreads
|
|
7113
|
-
}));
|
|
7114
|
-
//#endregion
|
|
7115
|
-
//#region ../contracts/src/plan-calls.ts
|
|
7116
|
-
/**
|
|
7117
|
-
* Plans and decisions: what the Worker asks a thread's Project DO, once `Authorize` has said
|
|
7118
|
-
* who's acting. A plan is written with its words; the Project DO stores each as a text and
|
|
7119
|
-
* records the version with their IDs.
|
|
7120
|
-
*/
|
|
7121
|
-
/** A plan's free text: one of its outcomes, or an answer's reason. */
|
|
7122
|
-
const PlanText = Schema.String.check(Schema.isBetweenLength(1, 2048));
|
|
7123
|
-
/**
|
|
7124
|
-
* How a plan does its work, in system terms, for people: about a page. A revision replaces it,
|
|
7125
|
-
* with a reason; no one appends to it.
|
|
7126
|
-
*/
|
|
7127
|
-
const Approach = Schema.String.check(Schema.isBetweenLength(1, 6e3));
|
|
7128
|
-
/**
|
|
7129
|
-
* A child as written. On a top-level org thread's plan, `project` names one of its owner's
|
|
7130
|
-
* projects to start it in, as that project's thread; left out, it's in its parent's scope.
|
|
7131
|
-
*/
|
|
7132
|
-
const PlanChildInput = Schema.Struct({
|
|
7133
|
-
entry: PlanEntryKey,
|
|
7134
|
-
title: Title,
|
|
7135
|
-
outcome: Outcome,
|
|
7136
|
-
stackedOn: Schema.optionalKey(PlanEntryKey),
|
|
7137
|
-
required: Schema.Boolean,
|
|
7138
|
-
project: Schema.optionalKey(ProjectName)
|
|
7139
|
-
});
|
|
7140
|
-
/**
|
|
7141
|
-
* A plan as written: `PlanRecord`'s shape, with its words in place of text IDs. Its repos are up
|
|
7142
|
-
* to 20 of the project's, by name; a parent whose work is all in its children names none.
|
|
7143
|
-
*/
|
|
7144
|
-
const PlanInput = Schema.Struct({
|
|
7145
|
-
approach: Schema.optionalKey(Approach),
|
|
7146
|
-
repos: Schema.Array(RepoName).check(Schema.isMaxLength(20)),
|
|
7147
|
-
outcomes: Schema.Array(PlanText).check(Schema.isBetweenLength(1, 50)),
|
|
7148
|
-
children: Schema.Array(PlanChildInput).check(Schema.isMaxLength(50))
|
|
7149
|
-
}).check(Schema.makeFilter((plan) => planProblem(plan) ?? true));
|
|
7150
|
-
/**
|
|
7151
|
-
* A project a plan's child names, as the Worker found it in the plan's owner before it asked the
|
|
7152
|
-
* scope: its ID, and whether the writer can see it; or, with no `project`, that the owner has
|
|
7153
|
-
* none by that name. The Worker refuses nothing for it, since only the scope knows which entries
|
|
7154
|
-
* a version keeps.
|
|
7155
|
-
*/
|
|
7156
|
-
const NamedProject = Schema.Struct({
|
|
7157
|
-
name: ProjectName,
|
|
7158
|
-
project: Schema.optionalKey(ProjectId),
|
|
7159
|
-
seen: Schema.Boolean
|
|
7160
|
-
});
|
|
7161
|
-
Schema.Struct({
|
|
7162
|
-
...commandFields,
|
|
7163
|
-
project: ProjectId,
|
|
7164
|
-
ownerName: OwnerName,
|
|
7165
|
-
number: ThreadNumber,
|
|
7166
|
-
plan: PlanInput,
|
|
7167
|
-
projects: Schema.Array(NamedProject).check(Schema.isMaxLength(50)),
|
|
7168
|
-
reason: Schema.optionalKey(Reason),
|
|
7169
|
-
propose: Schema.Boolean
|
|
7170
|
-
});
|
|
7171
|
-
Schema.Struct({
|
|
7172
|
-
...commandFields,
|
|
7173
|
-
ownerName: OwnerName,
|
|
7174
|
-
project: ProjectId,
|
|
7175
|
-
number: ThreadNumber,
|
|
7176
|
-
version: PlanVersion
|
|
7177
|
-
});
|
|
7178
|
-
/** A decision as it stands: what it asks, who decides, the answers so far, and how it closed. */
|
|
7179
|
-
const DecisionView = Schema.Struct({
|
|
7180
|
-
decision: DecisionId,
|
|
7181
|
-
kind: DecisionKind,
|
|
7182
|
-
subject: DecisionSubject,
|
|
7183
|
-
question: Schema.optionalKey(TextId),
|
|
7184
|
-
options: Schema.Array(AnswerOption),
|
|
7185
|
-
lean: Schema.optionalKey(AnswerKey),
|
|
7186
|
-
deciders: Schema.Array(Decider),
|
|
7187
|
-
deadline: Schema.optionalKey(Schema.DateTimeUtcFromMillis),
|
|
7188
|
-
state: Schema.Literals(["open", "closed"]),
|
|
7189
|
-
answers: Schema.Array(Schema.Struct({
|
|
7190
|
-
decider: DeciderRef,
|
|
7191
|
-
answer: AnswerKey,
|
|
7192
|
-
reason: Schema.optionalKey(TextId),
|
|
7193
|
-
at: Schema.DateTimeUtcFromMillis
|
|
7194
|
-
})),
|
|
7195
|
-
result: Schema.optionalKey(AnswerKey),
|
|
7196
|
-
closedWhy: Schema.optionalKey(DecisionClosedWhy)
|
|
7197
|
-
});
|
|
7198
|
-
/**
|
|
7199
|
-
* A version as it stands: its content, its state, and, once proposed, where its approval is: its
|
|
7200
|
-
* repos still being checked, or who accepted it.
|
|
7201
|
-
*/
|
|
7202
|
-
const PlanVersionView = Schema.Struct({
|
|
7203
|
-
thread: ThreadId,
|
|
7204
|
-
number: ThreadNumber,
|
|
7205
|
-
version: PlanVersion,
|
|
7206
|
-
state: PlanState,
|
|
7207
|
-
contentHash: PlanContentHash,
|
|
7208
|
-
plan: PlanView,
|
|
7209
|
-
/** Why it was written, when its writer said: never part of its content. */
|
|
7210
|
-
reason: Schema.optionalKey(TextId),
|
|
7211
|
-
writtenBy: ActorRef,
|
|
7212
|
-
writtenAt: Schema.DateTimeUtcFromMillis,
|
|
7213
|
-
/** Proposed, and its repos haven't all answered yet: it isn't accepted yet. */
|
|
7214
|
-
checking: Schema.Boolean,
|
|
7215
|
-
/**
|
|
7216
|
-
* What its check found when it ended, every repo answered or their time run out: the repos
|
|
7217
|
-
* that never answered. None for a draft, while it's being checked, or when a newer version or
|
|
7218
|
-
* the thread closing ended the check first.
|
|
7219
|
-
*/
|
|
7220
|
-
check: Schema.optionalKey(PlanCheck),
|
|
7221
|
-
/**
|
|
7222
|
-
* Accepted, and waiting to be recorded: on its new `children` registering, or on a merge under
|
|
7223
|
-
* the thread's current revision `publishing`.
|
|
7224
|
-
*/
|
|
7225
|
-
accepting: Schema.optionalKey(Schema.Literals(["children", "publishing"])),
|
|
7226
|
-
acceptedBy: Schema.optionalKey(PlanAcceptedBy)
|
|
7227
|
-
});
|
|
7228
|
-
/** A plan's free text refused before anything was stored, saying which. */
|
|
7229
|
-
var PlanTextRefused = class extends Schema.TaggedError()("PlanTextRefused", {
|
|
7230
|
-
/** Where it is in the plan, such as `outcomes[3]`. */
|
|
7231
|
-
where: Schema.String,
|
|
7232
|
-
problem: Schema.Literals([
|
|
7233
|
-
"empty",
|
|
7234
|
-
"too long",
|
|
7235
|
-
"looks like a secret"
|
|
7236
|
-
]),
|
|
7237
|
-
nextStep: Schema.String
|
|
7238
|
-
}, { httpApiStatus: 422 }) {};
|
|
7239
|
-
/** A plan names a repo this project doesn't hold. */
|
|
7240
|
-
var PlanRepoNotFound = class extends Schema.TaggedError()("PlanRepoNotFound", {
|
|
7241
|
-
repo: RepoName,
|
|
7242
|
-
nextStep: Schema.String
|
|
7243
|
-
}, { httpApiStatus: 422 }) {};
|
|
7244
|
-
/**
|
|
7245
|
-
* A plan names its scope's own repo, made just now, before the scope holds it. Nothing was kept
|
|
7246
|
-
* under the request's delivery ID, so the same request is written once it does.
|
|
7247
|
-
*/
|
|
7248
|
-
var OwnRepoNotReady = class extends Schema.TaggedError()("OwnRepoNotReady", {
|
|
7249
|
-
repo: RepoName,
|
|
7250
|
-
nextStep: Schema.String
|
|
7251
|
-
}, { httpApiStatus: 503 }) {};
|
|
7252
|
-
/**
|
|
7253
|
-
* A child entry this plan can't have: a project named on a project thread's plan or a nested org
|
|
7254
|
-
* thread's, a project that isn't there or the writer can't see, one where its proposer may not
|
|
7255
|
-
* start threads, an entry moved to another project, or a stack across scopes. A project that
|
|
7256
|
-
* isn't there and one the writer can't see are refused alike, as `ProjectNotFound` is.
|
|
7257
|
-
*/
|
|
7258
|
-
var PlanChildRefused = class extends Schema.TaggedError()("PlanChildRefused", { nextStep: Schema.String }, { httpApiStatus: 422 }) {};
|
|
7259
|
-
var PlanVersionNotFound = class extends Schema.TaggedError()("PlanVersionNotFound", {
|
|
7260
|
-
number: ThreadNumber,
|
|
7261
|
-
version: PlanVersion,
|
|
7262
|
-
nextStep: Schema.String
|
|
7263
|
-
}, { httpApiStatus: 404 }) {};
|
|
7264
|
-
/**
|
|
7265
|
-
* Only a thread's newest version is proposed, and never one already declined, nor one whose
|
|
7266
|
-
* required or stacked children would close a cycle of threads waiting on each other.
|
|
6910
|
+
* Only a thread's newest version is proposed, and never one already declined, nor one whose
|
|
6911
|
+
* required or stacked children would close a cycle of threads waiting on each other.
|
|
7267
6912
|
*/
|
|
7268
6913
|
var PlanNotProposable = class extends Schema.TaggedError()("PlanNotProposable", {
|
|
7269
6914
|
version: PlanVersion,
|
|
@@ -7334,126 +6979,525 @@ var AnswerRefused = class extends Schema.TaggedError()("AnswerRefused", {
|
|
|
7334
6979
|
nextStep: Schema.String
|
|
7335
6980
|
}, { httpApiStatus: 409 }) {};
|
|
7336
6981
|
/**
|
|
7337
|
-
* Where a gate's answer goes: its Repo DO, which alone decides it, named by the gate's subject,
|
|
7338
|
-
* with the answer's reason already stored here, where the fold reads it, and the scope it's in,
|
|
7339
|
-
* which the Worker's `nextStep`s write. The Project DO keeps no receipt for a route, so a
|
|
7340
|
-
* retry routes again, and the Repo DO keeps the answer's. The Worker takes it and never answers
|
|
7341
|
-
* with it.
|
|
6982
|
+
* Where a gate's answer goes: its Repo DO, which alone decides it, named by the gate's subject,
|
|
6983
|
+
* with the answer's reason already stored here, where the fold reads it, and the scope it's in,
|
|
6984
|
+
* which the Worker's `nextStep`s write. The Project DO keeps no receipt for a route, so a
|
|
6985
|
+
* retry routes again, and the Repo DO keeps the answer's. The Worker takes it and never answers
|
|
6986
|
+
* with it.
|
|
6987
|
+
*/
|
|
6988
|
+
const GateAnswerRoute = Schema.TaggedStruct("GateAnswerRoute", {
|
|
6989
|
+
scope: ThreadScope,
|
|
6990
|
+
decision: DecisionId,
|
|
6991
|
+
repo: RepoId,
|
|
6992
|
+
pullRequest: PullRequestNumber,
|
|
6993
|
+
version: VersionNumber,
|
|
6994
|
+
reason: Schema.optionalKey(TextId)
|
|
6995
|
+
});
|
|
6996
|
+
Schema.Union([
|
|
6997
|
+
NamedDecision,
|
|
6998
|
+
GateAnswerRoute,
|
|
6999
|
+
DecisionNotFound,
|
|
7000
|
+
AnswerRefused,
|
|
7001
|
+
PlanTextRefused,
|
|
7002
|
+
ProjectNotReady,
|
|
7003
|
+
ProjectNotFound,
|
|
7004
|
+
DeliveryOutsideWindow
|
|
7005
|
+
]);
|
|
7006
|
+
Schema.Struct({
|
|
7007
|
+
...commandFields,
|
|
7008
|
+
project: ProjectId,
|
|
7009
|
+
decision: DecisionId,
|
|
7010
|
+
pullRequest: PullRequestNumber,
|
|
7011
|
+
version: VersionNumber,
|
|
7012
|
+
answer: AnswerKey,
|
|
7013
|
+
reason: Schema.optionalKey(TextId),
|
|
7014
|
+
admin: Schema.Boolean
|
|
7015
|
+
});
|
|
7016
|
+
Schema.Union([
|
|
7017
|
+
Schema.Struct({
|
|
7018
|
+
outcome: Schema.Literal("answered"),
|
|
7019
|
+
deciders: Schema.Array(DeciderRef)
|
|
7020
|
+
}),
|
|
7021
|
+
Schema.Struct({ outcome: Schema.Literals([
|
|
7022
|
+
"decision closed",
|
|
7023
|
+
"not a decider",
|
|
7024
|
+
"already answered",
|
|
7025
|
+
"not an answer"
|
|
7026
|
+
]) }),
|
|
7027
|
+
DeliveryOutsideWindow
|
|
7028
|
+
]);
|
|
7029
|
+
/** Someone decisions wait on: a person, or an agent, and the roles the Worker found they hold. */
|
|
7030
|
+
const Waiter = Schema.Struct({
|
|
7031
|
+
decider: DeciderRef,
|
|
7032
|
+
roles: Schema.Array(Schema.Struct({
|
|
7033
|
+
role: Schema.Literal("admin"),
|
|
7034
|
+
owner: OwnerId
|
|
7035
|
+
}))
|
|
7036
|
+
});
|
|
7037
|
+
Schema.Struct({
|
|
7038
|
+
ownerName: OwnerName,
|
|
7039
|
+
you: Waiter,
|
|
7040
|
+
person: Schema.optionalKey(Waiter),
|
|
7041
|
+
decisions: Schema.optionalKey(Schema.Array(DecisionId).check(Schema.isMaxLength(100)))
|
|
7042
|
+
});
|
|
7043
|
+
/**
|
|
7044
|
+
* An open decision that waits on the caller: on them, or, for an agent, on its person, who
|
|
7045
|
+
* answers it. A gate never takes an agent's answer, so an agent's gate always waits on its person.
|
|
7046
|
+
*/
|
|
7047
|
+
const WaitingDecision = Schema.Struct({
|
|
7048
|
+
...NamedDecision.fields,
|
|
7049
|
+
waitsOn: Schema.Literals(["you", "your person"])
|
|
7050
|
+
});
|
|
7051
|
+
const WaitingPage = Schema.Struct({ decisions: Schema.Array(WaitingDecision) });
|
|
7052
|
+
Schema.Struct({
|
|
7053
|
+
ownerName: OwnerName,
|
|
7054
|
+
number: ThreadNumber
|
|
7055
|
+
});
|
|
7056
|
+
const PlanVersionPage = Schema.Struct({ versions: Schema.Array(PlanVersionView) });
|
|
7057
|
+
Schema.Union([PlanVersionPage, ThreadNotFound]);
|
|
7058
|
+
/** One decision of the project's, by its ID. */
|
|
7059
|
+
/** At most how long a read of a decision waits for it to close, in seconds. */
|
|
7060
|
+
const DecisionWait = Schema.Int.check(Schema.isBetween({
|
|
7061
|
+
minimum: 1,
|
|
7062
|
+
maximum: 60
|
|
7063
|
+
}));
|
|
7064
|
+
Schema.Struct({
|
|
7065
|
+
ownerName: OwnerName,
|
|
7066
|
+
decision: DecisionId,
|
|
7067
|
+
wait: Schema.optionalKey(DecisionWait)
|
|
7068
|
+
});
|
|
7069
|
+
Schema.Union([NamedDecision, DecisionNotFound]);
|
|
7070
|
+
/**
|
|
7071
|
+
* `POST …/plans`: a version, as a draft unless it's proposed at once, and why it was written.
|
|
7072
|
+
* A first version needs no reason, and a later one may leave it out.
|
|
7073
|
+
*/
|
|
7074
|
+
const WritePlanRequest = Schema.Struct({
|
|
7075
|
+
plan: PlanInput,
|
|
7076
|
+
reason: Schema.optionalKey(Reason),
|
|
7077
|
+
propose: Schema.optionalKey(Schema.Boolean)
|
|
7078
|
+
});
|
|
7079
|
+
/** `POST …/decisions/{decision}/answers`: one of its answers, and why, in words. */
|
|
7080
|
+
const AnswerRequest = Schema.Struct({
|
|
7081
|
+
answer: AnswerKey,
|
|
7082
|
+
reason: Schema.optionalKey(PlanText)
|
|
7083
|
+
});
|
|
7084
|
+
Schema.Struct({
|
|
7085
|
+
thread: ThreadId,
|
|
7086
|
+
owner: OwnerId,
|
|
7087
|
+
parent: ThreadId,
|
|
7088
|
+
parentScope: ProjectId,
|
|
7089
|
+
parentNumber: ThreadNumber,
|
|
7090
|
+
fromPlan: Schema.Struct({
|
|
7091
|
+
version: PlanVersion,
|
|
7092
|
+
entry: PlanEntryKey
|
|
7093
|
+
}),
|
|
7094
|
+
title: Title,
|
|
7095
|
+
outcome: Outcome,
|
|
7096
|
+
required: Schema.Boolean,
|
|
7097
|
+
actor: ActorRef,
|
|
7098
|
+
cause: EventRef
|
|
7099
|
+
});
|
|
7100
|
+
/** The child as it stands, whether this call started it or an earlier one did. */
|
|
7101
|
+
const RemoteChildStarted = Schema.Struct({
|
|
7102
|
+
number: ThreadNumber,
|
|
7103
|
+
stage: ThreadStage,
|
|
7104
|
+
stageRevision: StageRevision
|
|
7105
|
+
});
|
|
7106
|
+
Schema.Union([RemoteChildStarted, ProjectNotReady]);
|
|
7107
|
+
Schema.Struct({
|
|
7108
|
+
thread: ThreadId,
|
|
7109
|
+
number: ThreadNumber
|
|
7110
|
+
});
|
|
7111
|
+
/** A child's stage and its revision, as one read found them. */
|
|
7112
|
+
const ChildStageView = Schema.Struct({
|
|
7113
|
+
stage: ThreadStage,
|
|
7114
|
+
stageRevision: StageRevision
|
|
7115
|
+
});
|
|
7116
|
+
Schema.Union([ChildStageView, ThreadNotFound]);
|
|
7117
|
+
//#endregion
|
|
7118
|
+
//#region ../contracts/src/approvals.ts
|
|
7119
|
+
/**
|
|
7120
|
+
* Approvals, as their commands travel: what a terminal, a page or an agent asks its person to
|
|
7121
|
+
* say yes to. A command is one endpoint, by its name in the surface table, and its request, as
|
|
7122
|
+
* that endpoint encodes it. ref0 decodes each part by the endpoint's own `Schema` before it
|
|
7123
|
+
* keeps or shows anything, so a command is exactly what the endpoint would take.
|
|
7124
|
+
*/
|
|
7125
|
+
/**
|
|
7126
|
+
* An endpoint by its name in the surface table, `group.endpoint`. Checked against the table
|
|
7127
|
+
* where the command is made canonical, since the table is typed from the API this is part of.
|
|
7128
|
+
*/
|
|
7129
|
+
const CommandEndpoint = Schema.String.check(Schema.isPattern(/^[a-zA-Z]+\.[a-zA-Z]+$/));
|
|
7130
|
+
/** One command, as asked: its endpoint, and its request's path, query and payload, encoded. */
|
|
7131
|
+
const ApprovalCommand = Schema.Struct({
|
|
7132
|
+
endpoint: CommandEndpoint,
|
|
7133
|
+
params: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)),
|
|
7134
|
+
query: Schema.optionalKey(Schema.JsonObject),
|
|
7135
|
+
payload: Schema.optionalKey(Schema.Json)
|
|
7136
|
+
});
|
|
7137
|
+
/** A command ref0 won't ask anyone about: not an endpoint's request, or not one an approval runs. */
|
|
7138
|
+
var CommandRefused = class extends Schema.TaggedError()("CommandRefused", { nextStep: Schema.String }, { httpApiStatus: 400 }) {};
|
|
7139
|
+
/** A terminal asking: its command, and the hash of the secret it collects the result with. */
|
|
7140
|
+
const StartApproval = Schema.Struct({
|
|
7141
|
+
command: ApprovalCommand,
|
|
7142
|
+
secretHash: SecretHash
|
|
7143
|
+
});
|
|
7144
|
+
/** A terminal's approval, started: what to show its person, and until when. */
|
|
7145
|
+
const ApprovalStarted = Schema.Struct({
|
|
7146
|
+
approval: ApprovalId,
|
|
7147
|
+
code: ApprovalCode,
|
|
7148
|
+
expiresAt: Timestamp
|
|
7149
|
+
});
|
|
7150
|
+
/**
|
|
7151
|
+
* An answer that waits for the person: the call only the person may make, or that agents ask
|
|
7152
|
+
* for, became an approval, which the person answers on their own page. A `202`, never a failure
|
|
7153
|
+
* of the call: whoever asked collects the result with `GET /v1/approvals/{approval}`.
|
|
7154
|
+
*/
|
|
7155
|
+
var ApprovalNeeded = class extends Schema.TaggedError()("ApprovalNeeded", {
|
|
7156
|
+
approval: ApprovalId,
|
|
7157
|
+
says: Schema.String,
|
|
7158
|
+
expiresAt: Timestamp
|
|
7159
|
+
}, { httpApiStatus: 202 }) {};
|
|
7160
|
+
const terminalAsker = Schema.Struct({ kind: Schema.Literal("terminal") });
|
|
7161
|
+
const pageAsker = Schema.Struct({ kind: Schema.Literal("page") });
|
|
7162
|
+
const agentAsker = Schema.Struct({
|
|
7163
|
+
kind: Schema.Literal("agent"),
|
|
7164
|
+
agent: AgentId,
|
|
7165
|
+
handle: AgentHandle,
|
|
7166
|
+
session: SessionId,
|
|
7167
|
+
/** The attachment its credential was made under, for a person's agent in an organization. */
|
|
7168
|
+
attachment: Schema.optionalKey(CredentialRef)
|
|
7169
|
+
});
|
|
7170
|
+
/**
|
|
7171
|
+
* Who asked, as a receipt keeps it: a terminal, one of ref0's pages, an agent, or a machine
|
|
7172
|
+
* asking to connect, by its ID and its own word for itself, and from where.
|
|
7173
|
+
*/
|
|
7174
|
+
const ApprovalAsker = Schema.Union([
|
|
7175
|
+
terminalAsker,
|
|
7176
|
+
pageAsker,
|
|
7177
|
+
Schema.Struct({
|
|
7178
|
+
kind: Schema.Literal("machine"),
|
|
7179
|
+
machine: MachineId,
|
|
7180
|
+
machineName: MachineName,
|
|
7181
|
+
askedFrom: Schema.optionalKey(Schema.String)
|
|
7182
|
+
}),
|
|
7183
|
+
agentAsker
|
|
7184
|
+
]);
|
|
7185
|
+
/**
|
|
7186
|
+
* Who asked, as the person reads a request before they answer: a terminal, a page or an agent.
|
|
7187
|
+
* A machine's request is read as an `AttachmentRequestView`, never as a command.
|
|
7188
|
+
*/
|
|
7189
|
+
const ApprovalViewAsker = Schema.Union([
|
|
7190
|
+
terminalAsker,
|
|
7191
|
+
pageAsker,
|
|
7192
|
+
agentAsker
|
|
7193
|
+
]);
|
|
7194
|
+
/** A request, as the person reads it before they answer. */
|
|
7195
|
+
const ApprovalView = Schema.Struct({
|
|
7196
|
+
approval: ApprovalId,
|
|
7197
|
+
/** The command as its CLI line. */
|
|
7198
|
+
says: Schema.String,
|
|
7199
|
+
/** Everything the command carries, each named, in order: nothing it would run is left out. */
|
|
7200
|
+
fields: Schema.Array(Schema.Struct({
|
|
7201
|
+
name: Schema.String,
|
|
7202
|
+
value: Schema.String,
|
|
7203
|
+
part: Schema.Literals([
|
|
7204
|
+
"path",
|
|
7205
|
+
"query",
|
|
7206
|
+
"payload"
|
|
7207
|
+
])
|
|
7208
|
+
})),
|
|
7209
|
+
command: ApprovalCommand,
|
|
7210
|
+
asker: ApprovalViewAsker,
|
|
7211
|
+
askedFrom: Schema.optionalKey(Schema.String),
|
|
7212
|
+
askedAt: Timestamp,
|
|
7213
|
+
expiresAt: Timestamp,
|
|
7214
|
+
/**
|
|
7215
|
+
* An agent's ask: the kind of action its answer may set agents' permission for, and whether a
|
|
7216
|
+
* yes may let agents take it without asking. A no with the passkey may always stop them asking.
|
|
7217
|
+
*/
|
|
7218
|
+
agentPermission: Schema.optionalKey(Schema.Struct({
|
|
7219
|
+
action: ScopeAction,
|
|
7220
|
+
mayAllow: Schema.Boolean
|
|
7221
|
+
})),
|
|
7222
|
+
/**
|
|
7223
|
+
* What the command acts on, drawn as ref0 resolves it for the person reading, where its
|
|
7224
|
+
* endpoint names a preview. Without one the page can draw, it offers only no.
|
|
7225
|
+
*/
|
|
7226
|
+
preview: Schema.optionalKey(ApprovalPreview)
|
|
7227
|
+
});
|
|
7228
|
+
/** A statement's hash: the SHA-256 of its words and quoted values as JSON, as lowercase hex. */
|
|
7229
|
+
const StatementHash = Schema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/));
|
|
7230
|
+
/**
|
|
7231
|
+
* Who asks for a yes to a statement: a workflow's run, `passkey.run`'s, by the workflow and the
|
|
7232
|
+
* run; or a gate's check, `passkey.check`'s, by the check, the pull request's version it gates and
|
|
7233
|
+
* the check run its statement is over.
|
|
7234
|
+
*/
|
|
7235
|
+
const StatementAsker = Schema.Union([Schema.Struct({
|
|
7236
|
+
kind: Schema.Literal("workflow"),
|
|
7237
|
+
workflow: WorkflowName,
|
|
7238
|
+
run: WorkflowRunId
|
|
7239
|
+
}), Schema.Struct({
|
|
7240
|
+
kind: Schema.Literal("gate"),
|
|
7241
|
+
check: CheckKey,
|
|
7242
|
+
pullRequest: PullRequestNumber,
|
|
7243
|
+
version: VersionNumber,
|
|
7244
|
+
run: CheckRunId
|
|
7245
|
+
})]);
|
|
7246
|
+
/**
|
|
7247
|
+
* A passkey request, as the person reads it before they answer: the statement, its words as its
|
|
7248
|
+
* asker wrote them and each value it quotes, and its hash; who asks; where, a workflow's
|
|
7249
|
+
* `owner/repo` or a thread's `owner/project#number`, or a gate's pull request, `owner/repo#number`;
|
|
7250
|
+
* whom it asks, the run's accountable person, or for a gate the person behind its run, a person by
|
|
7251
|
+
* name, or a permission's holders; and until when.
|
|
7252
|
+
*/
|
|
7253
|
+
const StatementView = Schema.Struct({
|
|
7254
|
+
approval: ApprovalId,
|
|
7255
|
+
statement: WorkflowText,
|
|
7256
|
+
hash: StatementHash,
|
|
7257
|
+
asker: StatementAsker,
|
|
7258
|
+
home: Schema.String,
|
|
7259
|
+
from: Schema.Union([Schema.Literals(["accountable", "person"]), Schema.Struct({ permission: RepoPermissionName })]),
|
|
7260
|
+
askedAt: Timestamp,
|
|
7261
|
+
expiresAt: Timestamp
|
|
7262
|
+
});
|
|
7263
|
+
/**
|
|
7264
|
+
* The person's own requests, waiting for them; the passkey requests workflows' runs and gates asked
|
|
7265
|
+
* them; each machine's request this browser session is the answerer of, so a reload finds it
|
|
7266
|
+
* again without its code; and the gates' decisions that wait on their yes or no, in every project
|
|
7267
|
+
* they see, oldest first.
|
|
7268
|
+
*/
|
|
7269
|
+
const ApprovalsWaiting = Schema.Struct({
|
|
7270
|
+
approvals: Schema.Array(ApprovalView),
|
|
7271
|
+
statements: Schema.Array(StatementView),
|
|
7272
|
+
requests: Schema.Array(AttachmentRequestView),
|
|
7273
|
+
decisions: Schema.Array(NamedDecision)
|
|
7274
|
+
});
|
|
7275
|
+
/** Finding a terminal's request by the code it showed. */
|
|
7276
|
+
const FindApproval = Schema.Union([Schema.Struct({ code: TypedApprovalCode }), Schema.Struct({ link: Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{22}$/)) })]);
|
|
7277
|
+
/**
|
|
7278
|
+
* Asking for the passkey's options to answer a request: a terminal's request needs its code
|
|
7279
|
+
* again, so its ID alone, which travels where its code doesn't, never answers it. A machine's
|
|
7280
|
+
* request needs its answerer, and the agent it chooses to connect, before a yes has options.
|
|
7281
|
+
*/
|
|
7282
|
+
const ApprovalOptionsRequest = Schema.Struct({
|
|
7283
|
+
code: Schema.optionalKey(TypedApprovalCode),
|
|
7284
|
+
folders: Schema.optionalKey(ConnectFolderChoices)
|
|
7285
|
+
});
|
|
7286
|
+
/**
|
|
7287
|
+
* An answer: yes, with the passkey, or no. For an agent's ask, each answer can set the owner's
|
|
7288
|
+
* permission its own way, so a pairing that can't happen can't be sent: yes, and let agents do
|
|
7289
|
+
* it without asking; no, and stop agents asking, with the passkey too.
|
|
7290
|
+
*/
|
|
7291
|
+
const AnswerApproval = Schema.Union([
|
|
7292
|
+
Schema.Struct({
|
|
7293
|
+
answer: Schema.Literal("yes"),
|
|
7294
|
+
permission: Schema.optionalKey(Schema.Literal("allow")),
|
|
7295
|
+
assertion: PasskeyAsserted,
|
|
7296
|
+
code: Schema.optionalKey(TypedApprovalCode),
|
|
7297
|
+
/** The preview the page drew, where the command's endpoint names one. */
|
|
7298
|
+
preview: Schema.optionalKey(PreviewEcho),
|
|
7299
|
+
/** The statement the page showed, by its hash, for a workflow run's or a gate's passkey request. */
|
|
7300
|
+
statement: Schema.optionalKey(Schema.Struct({ hash: StatementHash }))
|
|
7301
|
+
}),
|
|
7302
|
+
Schema.Struct({
|
|
7303
|
+
answer: Schema.Literal("no"),
|
|
7304
|
+
permission: Schema.Literal("deny"),
|
|
7305
|
+
assertion: PasskeyAsserted,
|
|
7306
|
+
code: Schema.optionalKey(TypedApprovalCode)
|
|
7307
|
+
}),
|
|
7308
|
+
Schema.Struct({
|
|
7309
|
+
answer: Schema.Literal("no"),
|
|
7310
|
+
code: Schema.optionalKey(TypedApprovalCode)
|
|
7311
|
+
})
|
|
7312
|
+
]);
|
|
7313
|
+
/**
|
|
7314
|
+
* What running an approved command came to: its status, and its endpoint's answer or refusal,
|
|
7315
|
+
* as JSON. ref0 reads it by the command's endpoint before anyone sees it, and whoever asked reads
|
|
7316
|
+
* it the same way, with `ranOf`: this schema is part of the API the endpoints' types come from,
|
|
7317
|
+
* so it can't be typed by them itself.
|
|
7318
|
+
*/
|
|
7319
|
+
const Ran = Schema.Struct({
|
|
7320
|
+
status: Schema.Int,
|
|
7321
|
+
result: Schema.Json
|
|
7322
|
+
});
|
|
7323
|
+
/**
|
|
7324
|
+
* A ran command whose answer its endpoint's schemas no longer read, such as one kept from
|
|
7325
|
+
* before they changed: it ran, and what it came to can't be said.
|
|
7326
|
+
*/
|
|
7327
|
+
var ResultUnreadable = class extends Schema.TaggedError()("ResultUnreadable", { nextStep: Schema.String }, { httpApiStatus: 500 }) {};
|
|
7328
|
+
/**
|
|
7329
|
+
* Where a request stands, for whoever asked: still waiting; approved, and running as soon as
|
|
7330
|
+
* ref0 can; refused; expired; or what it ran to, with the endpoint it ran, whose schemas read it.
|
|
7331
|
+
*/
|
|
7332
|
+
const ApprovalState = Schema.Union([
|
|
7333
|
+
Schema.Struct({
|
|
7334
|
+
state: Schema.Literal("waiting"),
|
|
7335
|
+
expiresAt: Timestamp
|
|
7336
|
+
}),
|
|
7337
|
+
Schema.Struct({
|
|
7338
|
+
state: Schema.Literal("approved"),
|
|
7339
|
+
/** A machine's answering browser may forget its saved answer once the terminal kept it. */
|
|
7340
|
+
collected: Schema.optionalKey(Schema.Literal(true))
|
|
7341
|
+
}),
|
|
7342
|
+
Schema.Struct({ state: Schema.Literal("refused") }),
|
|
7343
|
+
Schema.Struct({ state: Schema.Literal("expired") }),
|
|
7344
|
+
Schema.Struct({
|
|
7345
|
+
state: Schema.Literal("ran"),
|
|
7346
|
+
endpoint: CommandEndpoint,
|
|
7347
|
+
...Ran.fields
|
|
7348
|
+
})
|
|
7349
|
+
]);
|
|
7350
|
+
/** Only the answering browser receives a machine's answer code; state reads never carry it. */
|
|
7351
|
+
const ApprovalAnswer = Schema.Union([
|
|
7352
|
+
Schema.Struct({
|
|
7353
|
+
...ApprovalState.members[1].fields,
|
|
7354
|
+
answerCode: ApprovalCode
|
|
7355
|
+
}),
|
|
7356
|
+
Schema.Struct({
|
|
7357
|
+
...ApprovalState.members[4].fields,
|
|
7358
|
+
answerCode: ApprovalCode
|
|
7359
|
+
}),
|
|
7360
|
+
ApprovalState
|
|
7361
|
+
]);
|
|
7362
|
+
/** A request that isn't there, or isn't the caller's to see, answers the same. */
|
|
7363
|
+
var ApprovalNotFound = class extends Schema.TaggedError()("ApprovalNotFound", { nextStep: Schema.String }, { httpApiStatus: 404 }) {};
|
|
7364
|
+
/** Too many asked, or too many codes typed, from here in the last hour. */
|
|
7365
|
+
var SlowDown = class extends Schema.TaggedError()("SlowDown", { nextStep: Schema.String }, { httpApiStatus: 429 }) {};
|
|
7366
|
+
/** A command's hash: the SHA-256 of its canonical JSON, as lowercase hex. */
|
|
7367
|
+
const CommandHash = Schema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/));
|
|
7368
|
+
Schema.Struct({
|
|
7369
|
+
approval: ApprovalId,
|
|
7370
|
+
endpoint: CommandEndpoint,
|
|
7371
|
+
/** The command's canonical JSON. */
|
|
7372
|
+
command: Schema.String,
|
|
7373
|
+
commandHash: CommandHash,
|
|
7374
|
+
asker: ApprovalAsker,
|
|
7375
|
+
/** The browser session the person answered in, for their log. */
|
|
7376
|
+
credential: CredentialRef,
|
|
7377
|
+
generation: Generation,
|
|
7378
|
+
/** When the request expires, in epoch milliseconds. */
|
|
7379
|
+
deadline: Schema.Int,
|
|
7380
|
+
challenge: Schema.String,
|
|
7381
|
+
/** A machine answer retries only from its answering session, with this key. */
|
|
7382
|
+
answerKey: Schema.optionalKey(RequestId),
|
|
7383
|
+
/** An agent's ask: the credential it asked with, checked again before the answer counts. */
|
|
7384
|
+
asking: Schema.optionalKey(TokenId),
|
|
7385
|
+
/** The kind of action the person, answering, let agents take without asking from now on. */
|
|
7386
|
+
allow: Schema.optionalKey(ScopeAction)
|
|
7387
|
+
});
|
|
7388
|
+
Schema.Struct({
|
|
7389
|
+
approval: ApprovalId,
|
|
7390
|
+
action: ScopeAction,
|
|
7391
|
+
credential: CredentialRef,
|
|
7392
|
+
generation: Generation
|
|
7393
|
+
});
|
|
7394
|
+
Schema.Union([Schema.Struct({ denied: Schema.Literal(true) }), Schema.Struct({
|
|
7395
|
+
denied: Schema.Literal(false),
|
|
7396
|
+
reason: Schema.Literals(["generation moved", "not set up"])
|
|
7397
|
+
})]);
|
|
7398
|
+
Schema.Union([Schema.Struct({
|
|
7399
|
+
admitted: Schema.Literal(true),
|
|
7400
|
+
admittedAt: Schema.Int,
|
|
7401
|
+
answerCode: Schema.optionalKey(ApprovalCode)
|
|
7402
|
+
}), Schema.Struct({
|
|
7403
|
+
admitted: Schema.Literal(false),
|
|
7404
|
+
reason: Schema.Literals([
|
|
7405
|
+
"expired",
|
|
7406
|
+
"generation moved",
|
|
7407
|
+
"challenge used",
|
|
7408
|
+
"not set up",
|
|
7409
|
+
"asker gone"
|
|
7410
|
+
])
|
|
7411
|
+
})]);
|
|
7412
|
+
Schema.Union([Schema.Struct({ found: Schema.Literal(false) }), Schema.Struct({
|
|
7413
|
+
found: Schema.Literal(true),
|
|
7414
|
+
endpoint: CommandEndpoint,
|
|
7415
|
+
command: Schema.String,
|
|
7416
|
+
commandHash: CommandHash,
|
|
7417
|
+
generation: Generation,
|
|
7418
|
+
generationNow: Generation,
|
|
7419
|
+
/** The `approval.answered` its admission recorded in the person's log. */
|
|
7420
|
+
answeredEvent: EventId,
|
|
7421
|
+
/** Who asked, as that `approval.answered` says. */
|
|
7422
|
+
asker: ApprovalAsker,
|
|
7423
|
+
/** What running it came to, once it ran, as `KeptRan` keeps it. */
|
|
7424
|
+
result: Schema.optionalKey(Schema.String)
|
|
7425
|
+
})]);
|
|
7426
|
+
/**
|
|
7427
|
+
* A `Ran` as it's kept, on its receipt and on its approval: its JSON, as text. The Owner DO
|
|
7428
|
+
* keeps it as it comes and runs no endpoint's schemas, so it's read only by its endpoint, with
|
|
7429
|
+
* `keptRan`, which refuses one they don't take.
|
|
7342
7430
|
*/
|
|
7343
|
-
const
|
|
7344
|
-
scope: ThreadScope,
|
|
7345
|
-
decision: DecisionId,
|
|
7346
|
-
repo: RepoId,
|
|
7347
|
-
pullRequest: PullRequestNumber,
|
|
7348
|
-
version: VersionNumber,
|
|
7349
|
-
reason: Schema.optionalKey(TextId)
|
|
7350
|
-
});
|
|
7351
|
-
Schema.Union([
|
|
7352
|
-
DecisionView,
|
|
7353
|
-
GateAnswerRoute,
|
|
7354
|
-
DecisionNotFound,
|
|
7355
|
-
AnswerRefused,
|
|
7356
|
-
PlanTextRefused,
|
|
7357
|
-
ProjectNotReady,
|
|
7358
|
-
ProjectNotFound,
|
|
7359
|
-
DeliveryOutsideWindow
|
|
7360
|
-
]);
|
|
7361
|
-
Schema.Struct({
|
|
7362
|
-
...commandFields,
|
|
7363
|
-
project: ProjectId,
|
|
7364
|
-
decision: DecisionId,
|
|
7365
|
-
pullRequest: PullRequestNumber,
|
|
7366
|
-
version: VersionNumber,
|
|
7367
|
-
answer: AnswerKey,
|
|
7368
|
-
reason: Schema.optionalKey(TextId),
|
|
7369
|
-
admin: Schema.Boolean
|
|
7370
|
-
});
|
|
7371
|
-
Schema.Union([
|
|
7372
|
-
Schema.Struct({
|
|
7373
|
-
outcome: Schema.Literal("answered"),
|
|
7374
|
-
deciders: Schema.Array(DeciderRef)
|
|
7375
|
-
}),
|
|
7376
|
-
Schema.Struct({ outcome: Schema.Literals([
|
|
7377
|
-
"decision closed",
|
|
7378
|
-
"not a decider",
|
|
7379
|
-
"already answered",
|
|
7380
|
-
"not an answer"
|
|
7381
|
-
]) }),
|
|
7382
|
-
DeliveryOutsideWindow
|
|
7383
|
-
]);
|
|
7431
|
+
const KeptRan = Schema.fromJsonString(Ran);
|
|
7384
7432
|
Schema.Struct({
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
role: Schema.Literal("admin"),
|
|
7388
|
-
owner: OwnerId
|
|
7389
|
-
})))
|
|
7433
|
+
approval: ApprovalId,
|
|
7434
|
+
result: Schema.String
|
|
7390
7435
|
});
|
|
7391
|
-
|
|
7436
|
+
Schema.Struct({ result: Schema.String });
|
|
7437
|
+
Schema.Struct({ approval: ApprovalId });
|
|
7438
|
+
Schema.Struct({ approval: ApprovalId });
|
|
7439
|
+
Schema.Union([Schema.Struct({ expired: Schema.Literal(true) }), Schema.Struct({ expired: Schema.Literal(false) })]);
|
|
7392
7440
|
Schema.Struct({
|
|
7393
|
-
|
|
7394
|
-
|
|
7441
|
+
person: PersonId,
|
|
7442
|
+
approval: ApprovalId
|
|
7395
7443
|
});
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
/**
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7402
|
-
|
|
7403
|
-
|
|
7444
|
+
//#endregion
|
|
7445
|
+
//#region ../contracts/src/browser-sessions.ts
|
|
7446
|
+
/**
|
|
7447
|
+
* A browser session's cookie: Better Auth's, named for ref0, `Secure` and host-only on the
|
|
7448
|
+
* app's one origin. It holds the session's token, signed; the directory and the person's Owner DO hold
|
|
7449
|
+
* only the token's SHA-256.
|
|
7450
|
+
*/
|
|
7451
|
+
const browserSessionCookie = "__Secure-ref0.session_token";
|
|
7404
7452
|
Schema.Struct({
|
|
7405
|
-
|
|
7406
|
-
|
|
7407
|
-
|
|
7453
|
+
token: TokenId,
|
|
7454
|
+
secretHash: SecretHash,
|
|
7455
|
+
expiresAt: Schema.DateTimeUtcFromMillis
|
|
7408
7456
|
});
|
|
7409
|
-
Schema.
|
|
7457
|
+
Schema.Struct({ registered: Schema.Boolean });
|
|
7410
7458
|
/**
|
|
7411
|
-
*
|
|
7412
|
-
*
|
|
7459
|
+
* Where a signed-in person stands: naming, when the name their GitHub login gave was taken or
|
|
7460
|
+
* kept back, with that login as a suggestion; setting up, once their owner is made and before
|
|
7461
|
+
* it's ready with this session registered, which naming again finishes; or ready.
|
|
7413
7462
|
*/
|
|
7414
|
-
const
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
propose: Schema.optionalKey(Schema.Boolean)
|
|
7418
|
-
});
|
|
7419
|
-
/** `POST …/decisions/{decision}/answers`: one of its answers, and why, in words. */
|
|
7420
|
-
const AnswerRequest = Schema.Struct({
|
|
7421
|
-
answer: AnswerKey,
|
|
7422
|
-
reason: Schema.optionalKey(PlanText)
|
|
7423
|
-
});
|
|
7424
|
-
Schema.Struct({
|
|
7425
|
-
thread: ThreadId,
|
|
7463
|
+
const Welcome = Schema.Union([Schema.Struct({
|
|
7464
|
+
state: Schema.Literals(["ready", "setting up"]),
|
|
7465
|
+
person: PersonId,
|
|
7426
7466
|
owner: OwnerId,
|
|
7427
|
-
|
|
7428
|
-
|
|
7429
|
-
|
|
7430
|
-
|
|
7431
|
-
|
|
7432
|
-
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
|
|
7436
|
-
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7467
|
+
name: OwnerName
|
|
7468
|
+
}), Schema.Struct({
|
|
7469
|
+
state: Schema.Literal("naming"),
|
|
7470
|
+
person: PersonId,
|
|
7471
|
+
suggestion: Schema.optionalKey(Schema.String)
|
|
7472
|
+
})]);
|
|
7473
|
+
/**
|
|
7474
|
+
* A browser session renewed: its expiry, in its person's Owner DO and in the directory, and on its cookie.
|
|
7475
|
+
* Renewed at most once a day, so one asked sooner answers its expiry unchanged.
|
|
7476
|
+
*/
|
|
7477
|
+
const SessionRenewed = Schema.Struct({ expiresAt: Schema.DateTimeUtcFromMillis });
|
|
7478
|
+
/**
|
|
7479
|
+
* What starting a GitHub sign-in at `POST /auth/sign-in/social` answers: GitHub's address to go
|
|
7480
|
+
* to, with the sign-in's state in a cookie set alongside. Better Auth's answer, which ref0 serves.
|
|
7481
|
+
*/
|
|
7482
|
+
const NavigationUrl = Schema.String.check(Schema.isPattern(/^https?:\/\/[^\s/]+(?:\/[^\s]*)?$/), Schema.makeFilter((url) => URL.canParse(url) || "an HTTP(S) URL the platform can parse")).pipe(Schema.brand("NavigationUrl"));
|
|
7483
|
+
const SignInStarted = Schema.Struct({ url: NavigationUrl });
|
|
7484
|
+
/**
|
|
7485
|
+
* Where signing in sends the browser back to, as `POST /auth/sign-in/social` takes it: a path on
|
|
7486
|
+
* ref0's own origin, such as `/welcome`, or a whole URL. Never a socket's.
|
|
7487
|
+
*/
|
|
7488
|
+
const SignInDestination = Schema.String.pipe(Schema.brand("SignInDestination"));
|
|
7489
|
+
/**
|
|
7490
|
+
* What `POST /auth/sign-in/social` takes to start signing in with GitHub: where the browser
|
|
7491
|
+
* lands coming back, and where it lands when signing in failed. Better Auth's body, which ref0
|
|
7492
|
+
* serves.
|
|
7493
|
+
*/
|
|
7494
|
+
const StartSignIn = Schema.Struct({
|
|
7495
|
+
provider: Schema.Literal("github"),
|
|
7496
|
+
callbackURL: SignInDestination,
|
|
7497
|
+
errorCallbackURL: SignInDestination
|
|
7455
7498
|
});
|
|
7456
|
-
|
|
7499
|
+
/** The name a naming person chose for their owner. */
|
|
7500
|
+
const NameOwner = Schema.Struct({ name: OwnerName });
|
|
7457
7501
|
//#endregion
|
|
7458
7502
|
//#region ../contracts/src/ask-calls.ts
|
|
7459
7503
|
/**
|
|
@@ -10268,10 +10312,21 @@ signInRoute("POST", "/oauth2/consent");
|
|
|
10268
10312
|
*/
|
|
10269
10313
|
const oauthDiscoveryPaths = ["/.well-known/oauth-protected-resource/mcp", `${oauthRoutes.metadata.pathUnderBase}${signInBase}`];
|
|
10270
10314
|
/**
|
|
10315
|
+
* Where an outside service finds identity tokens' issuer and its public keys, each at the
|
|
10316
|
+
* origin's root: the issuer's discovery document, and its JWKS. Only these two: every other path
|
|
10317
|
+
* under `/.well-known/` is a page's.
|
|
10318
|
+
*/
|
|
10319
|
+
const identityDiscoveryRoutes = {
|
|
10320
|
+
configuration: "/.well-known/openid-configuration",
|
|
10321
|
+
keys: "/.well-known/jwks.json"
|
|
10322
|
+
};
|
|
10323
|
+
/** Whether a path is one of identity tokens' two published documents. */
|
|
10324
|
+
const isIdentityDiscoveryPath = (pathname) => pathname === identityDiscoveryRoutes.configuration || pathname === identityDiscoveryRoutes.keys;
|
|
10325
|
+
/**
|
|
10271
10326
|
* Whether a path is Worker "server"'s to answer, not a page's: the API's, signing in's, a
|
|
10272
|
-
* connection's webhook,
|
|
10327
|
+
* connection's webhook, OAuth's metadata, or identity tokens' published documents.
|
|
10273
10328
|
*/
|
|
10274
|
-
const isRef0Path = (pathname) => isSignInPath(pathname) || isHooksPath(pathname) || pathname === "/v1" || pathname.startsWith(`/v1/`) || oauthDiscoveryPaths.includes(pathname);
|
|
10329
|
+
const isRef0Path = (pathname) => isSignInPath(pathname) || isHooksPath(pathname) || pathname === "/v1" || pathname.startsWith(`/v1/`) || oauthDiscoveryPaths.includes(pathname) || isIdentityDiscoveryPath(pathname);
|
|
10275
10330
|
//#endregion
|
|
10276
10331
|
//#region ../contracts/src/live-calls.ts
|
|
10277
10332
|
/**
|
|
@@ -11584,6 +11639,151 @@ Schema.Struct({
|
|
|
11584
11639
|
name: RepoName
|
|
11585
11640
|
}))
|
|
11586
11641
|
});
|
|
11642
|
+
/** Where an agent's session asks for an identity token. */
|
|
11643
|
+
const identityTokenPath = "/v1/me/identity-token";
|
|
11644
|
+
/** One DNS label, or one part of an IPv4 address: letters, digits and inner hyphens. */
|
|
11645
|
+
const label = "[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?";
|
|
11646
|
+
/** `https://`, a host name, then maybe `:` and a port with no leading zero. */
|
|
11647
|
+
const audiencePattern = new RegExp(`^https://(${label}(?:\\.${label})*)(?::([1-9][0-9]{0,4}))?$`);
|
|
11648
|
+
/**
|
|
11649
|
+
* Whether the platform's URL parser reads the audience as written: an `https` URL whose host is
|
|
11650
|
+
* the audience's own, lowercased, and whose port is its own, or none for 443. That refuses a host
|
|
11651
|
+
* the parser rewrites, such as `https://1.2.3` read as `1.2.0.3`, and a port past 65535.
|
|
11652
|
+
*/
|
|
11653
|
+
const parsesAsWritten = (audience) => {
|
|
11654
|
+
const parts = audiencePattern.exec(audience);
|
|
11655
|
+
if (parts === null || !URL.canParse(audience)) return false;
|
|
11656
|
+
const url = new URL(audience);
|
|
11657
|
+
const port = parts[2] ?? "";
|
|
11658
|
+
return url.protocol === "https:" && url.hostname === (parts[1] ?? "").toLowerCase() && url.port === (port === "443" ? "" : port);
|
|
11659
|
+
};
|
|
11660
|
+
/**
|
|
11661
|
+
* Who an identity token is for: an outside service's HTTPS origin, in ASCII, at most 255 bytes,
|
|
11662
|
+
* with no credentials, path, query, fragment, wildcard or space. It's kept exactly as asked, its
|
|
11663
|
+
* case and any port too, so `https://verifier.example:443` is another audience than
|
|
11664
|
+
* `https://verifier.example`. ref0 never fetches or resolves it.
|
|
11665
|
+
*/
|
|
11666
|
+
const IdentityAudience = Schema.String.check(Schema.isMaxLength(255), Schema.isPattern(audiencePattern), Schema.makeFilter((audience) => parsesAsWritten(audience) || "an origin the platform reads as written")).pipe(Schema.brand("IdentityAudience"));
|
|
11667
|
+
/** `POST /v1/me/identity-token`'s body: the one audience, and nothing else. */
|
|
11668
|
+
const IdentityTokenRequest = Schema.Struct({ audience: IdentityAudience });
|
|
11669
|
+
/** A compact JWT: its header, payload and signature, each in base64url, at most 4 KiB. */
|
|
11670
|
+
const IdentityToken = Schema.String.check(Schema.isMaxLength(4096), Schema.isPattern(/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/)).pipe(Schema.brand("IdentityToken"));
|
|
11671
|
+
/** What asking for an identity token answers: the token, and when it expires, its `exp`. */
|
|
11672
|
+
const IssuedIdentityToken = Schema.Struct({
|
|
11673
|
+
token: IdentityToken,
|
|
11674
|
+
expiresAt: Schema.DateTimeUtcFromMillis
|
|
11675
|
+
});
|
|
11676
|
+
/**
|
|
11677
|
+
* An identity token's `jti`: a fresh UUIDv4 from the platform's cryptographic source for each
|
|
11678
|
+
* token, naming its issuance in ref0's log without naming any row or secret.
|
|
11679
|
+
*/
|
|
11680
|
+
const IdentityTokenId = Schema.String.check(Schema.isPattern(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/)).pipe(Schema.brand("IdentityTokenId"));
|
|
11681
|
+
/**
|
|
11682
|
+
* A person, as one audience knows them: `pperson_`, then the first 128 bits of an HMAC of the
|
|
11683
|
+
* person's ref0 ID for the token's issuer and audience, as a TypeID suffix. Stable at one
|
|
11684
|
+
* audience, different at every other, and carrying no time.
|
|
11685
|
+
*/
|
|
11686
|
+
const PairwisePersonId = TypeId("pperson").pipe(Schema.brand("PairwisePersonId"));
|
|
11687
|
+
/** A session, as one audience knows it, made as a person's is. */
|
|
11688
|
+
const PairwiseSessionId = TypeId("psession").pipe(Schema.brand("PairwiseSessionId"));
|
|
11689
|
+
/** The accountable person, last in a token's chain: only their pairwise ID. */
|
|
11690
|
+
const PersonActor = Schema.Struct({ sub: PairwisePersonId });
|
|
11691
|
+
/** A session in a token's chain, then whoever it acts for: its parent session, or the person. */
|
|
11692
|
+
const sessionActing = (act) => Schema.Struct({
|
|
11693
|
+
sub: PairwiseSessionId,
|
|
11694
|
+
act
|
|
11695
|
+
});
|
|
11696
|
+
const oneSession = sessionActing(PersonActor);
|
|
11697
|
+
const twoSessions = sessionActing(oneSession);
|
|
11698
|
+
const threeSessions = sessionActing(twoSessions);
|
|
11699
|
+
/**
|
|
11700
|
+
* A token's `act`, as RFC 8693 nests it: the current session, then up to three parent sessions,
|
|
11701
|
+
* then the accountable person, each by its pairwise ID. It's history, not authority: a verifier
|
|
11702
|
+
* allows the agent in `sub`, never an actor.
|
|
11703
|
+
*/
|
|
11704
|
+
const IdentityActor = Schema.Union([
|
|
11705
|
+
oneSession,
|
|
11706
|
+
twoSessions,
|
|
11707
|
+
threeSessions,
|
|
11708
|
+
sessionActing(threeSessions)
|
|
11709
|
+
]);
|
|
11710
|
+
/** A time in a token, in whole UTC epoch seconds. */
|
|
11711
|
+
const EpochSeconds = Schema.Int.check(Schema.isGreaterThan(0));
|
|
11712
|
+
Schema.Struct({
|
|
11713
|
+
iss: ApiOrigin,
|
|
11714
|
+
sub: AgentId,
|
|
11715
|
+
aud: IdentityAudience,
|
|
11716
|
+
iat: EpochSeconds,
|
|
11717
|
+
exp: EpochSeconds,
|
|
11718
|
+
jti: IdentityTokenId,
|
|
11719
|
+
act: IdentityActor
|
|
11720
|
+
}).check(Schema.makeFilter(({ iat, exp }) => exp > iat && exp - iat <= 600 || `an expiry after its issue, at most 600 seconds later`));
|
|
11721
|
+
/**
|
|
11722
|
+
* A signing key's ID, its `kid`: the key's RFC 7638 thumbprint, SHA-256 in base64url, so one ID
|
|
11723
|
+
* never names two keys.
|
|
11724
|
+
*/
|
|
11725
|
+
const SigningKeyId = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{43}$/)).pipe(Schema.brand("SigningKeyId"));
|
|
11726
|
+
Schema.Struct({
|
|
11727
|
+
alg: Schema.Literal("ES256"),
|
|
11728
|
+
kid: SigningKeyId,
|
|
11729
|
+
typ: Schema.Literal("JWT")
|
|
11730
|
+
});
|
|
11731
|
+
/** A P-256 coordinate: 32 bytes in base64url, unpadded, in its one canonical spelling. */
|
|
11732
|
+
const Coordinate = Schema.String.check(Schema.isPattern(/^[A-Za-z0-9_-]{42}[AEIMQUYcgkosw048]$/));
|
|
11733
|
+
/** One public key in the JWKS: exactly these fields, and never a private one. */
|
|
11734
|
+
const PublicSigningKey = Schema.Struct({
|
|
11735
|
+
kty: Schema.Literal("EC"),
|
|
11736
|
+
crv: Schema.Literal("P-256"),
|
|
11737
|
+
x: Coordinate,
|
|
11738
|
+
y: Coordinate,
|
|
11739
|
+
use: Schema.Literal("sig"),
|
|
11740
|
+
alg: Schema.Literal("ES256"),
|
|
11741
|
+
kid: SigningKeyId
|
|
11742
|
+
});
|
|
11743
|
+
Schema.Struct({ keys: Schema.Array(PublicSigningKey).check(Schema.isMaxLength(3)) });
|
|
11744
|
+
Schema.Struct({
|
|
11745
|
+
issuer: ApiOrigin,
|
|
11746
|
+
jwks_uri: Schema.String,
|
|
11747
|
+
subject_types_supported: Schema.Tuple([Schema.Literal("public")]),
|
|
11748
|
+
id_token_signing_alg_values_supported: Schema.Tuple([Schema.Literal("ES256")]),
|
|
11749
|
+
claims_supported: Schema.Tuple([
|
|
11750
|
+
Schema.Literal("iss"),
|
|
11751
|
+
Schema.Literal("sub"),
|
|
11752
|
+
Schema.Literal("aud"),
|
|
11753
|
+
Schema.Literal("exp"),
|
|
11754
|
+
Schema.Literal("iat"),
|
|
11755
|
+
Schema.Literal("jti"),
|
|
11756
|
+
Schema.Literal("act")
|
|
11757
|
+
])
|
|
11758
|
+
});
|
|
11759
|
+
/**
|
|
11760
|
+
* The audience isn't one ref0 signs for: missing, given twice, or not an HTTPS origin as
|
|
11761
|
+
* `IdentityAudience` says. The refused text is never echoed.
|
|
11762
|
+
*/
|
|
11763
|
+
var IdentityAudienceRefused = class extends Schema.TaggedError()("IdentityAudienceRefused", { nextStep: Schema.String }, { httpApiStatus: 400 }) {};
|
|
11764
|
+
/**
|
|
11765
|
+
* Less than a whole second is left before the session, a parent or the credential expires, or
|
|
11766
|
+
* the token would expire before it's recorded: the next prompt renews or replaces the session.
|
|
11767
|
+
*/
|
|
11768
|
+
var IdentityTokenNotReady = class extends Schema.TaggedError()("IdentityTokenNotReady", { nextStep: Schema.String }, { httpApiStatus: 409 }) {};
|
|
11769
|
+
/**
|
|
11770
|
+
* ref0 signed an identity token for one of a project's sessions: in that project's log, on the
|
|
11771
|
+
* session's thread, with ref0's own IDs for the session, its agent and its accountable person,
|
|
11772
|
+
* and the token's `jti`, never the token. It proves ref0 made the token, not that any service
|
|
11773
|
+
* received or used it. A failed append discards the token, so every token has its event.
|
|
11774
|
+
*/
|
|
11775
|
+
const IdentityTokenIssued = eventKind("identity_token.issued", Schema.Struct({
|
|
11776
|
+
session: SessionId,
|
|
11777
|
+
agent: AgentRef,
|
|
11778
|
+
/** The person whose attachment authorized the session's chain, last in the token's `act`. */
|
|
11779
|
+
accountable: PersonId,
|
|
11780
|
+
jti: IdentityTokenId,
|
|
11781
|
+
audience: IdentityAudience,
|
|
11782
|
+
issuer: ApiOrigin,
|
|
11783
|
+
keyId: SigningKeyId,
|
|
11784
|
+
issuedAt: Schema.DateTimeUtcFromMillis,
|
|
11785
|
+
expiresAt: Schema.DateTimeUtcFromMillis
|
|
11786
|
+
}));
|
|
11587
11787
|
Schema.Literals([
|
|
11588
11788
|
"info/refs",
|
|
11589
11789
|
"git-upload-pack",
|
|
@@ -11834,6 +12034,71 @@ const GateAddition = Schema.Struct({
|
|
|
11834
12034
|
from: NeedFrom
|
|
11835
12035
|
});
|
|
11836
12036
|
/**
|
|
12037
|
+
* A yes that met a need: its decider's, given by the person `by` when one gave it, such as an
|
|
12038
|
+
* admin answering as the owner's admins; or, `overridden`, a check ref0 said no to, met by the
|
|
12039
|
+
* yes of each of its overrides.
|
|
12040
|
+
*/
|
|
12041
|
+
const NeedYes = Schema.Struct({
|
|
12042
|
+
decider: DeciderRef,
|
|
12043
|
+
by: Schema.optionalKey(PersonId),
|
|
12044
|
+
overridden: Schema.optionalKey(Schema.Literal(true))
|
|
12045
|
+
});
|
|
12046
|
+
/**
|
|
12047
|
+
* An override left of a check ref0 said no to: of a part's failed run, or of the check not running,
|
|
12048
|
+
* and who answers it.
|
|
12049
|
+
*/
|
|
12050
|
+
const OverrideLeft = Schema.Struct({
|
|
12051
|
+
of: Schema.Literals(["failed run", "not run"]),
|
|
12052
|
+
by: OverrideAnswerer
|
|
12053
|
+
});
|
|
12054
|
+
/**
|
|
12055
|
+
* A decider a need waits on. For a check ref0 said no to, `overrides` lists each of its overrides
|
|
12056
|
+
* left, every one of whose yeses meets it in a pass's place, none when it has none: one yes to a
|
|
12057
|
+
* gate answers every decider its person may answer as, each override among them.
|
|
12058
|
+
*/
|
|
12059
|
+
const NeedWait = Schema.Struct({
|
|
12060
|
+
decider: DeciderRef,
|
|
12061
|
+
overrides: Schema.optionalKey(Schema.Array(OverrideLeft).check(Schema.isMaxLength(maxGateDeciders)))
|
|
12062
|
+
});
|
|
12063
|
+
/**
|
|
12064
|
+
* How one of a version's needs stands under its gate's answers now, as the gate is decided from
|
|
12065
|
+
* them: `met` by each yes in `by`; `met` with nothing to wait for, `as` `no checks`, for `checks`
|
|
12066
|
+
* when none of the repo's checks runs on the change, or `on the tip`, for a check only the merge
|
|
12067
|
+
* queue's tip runs, which judges it before `main` moves; `waiting` on each decider in `on`, when
|
|
12068
|
+
* `all`, or else on a yes from any one of them; `waiting` for ref0 to read which of `main`'s
|
|
12069
|
+
* checks run on the change; or `refused` by a person's no to one of its deciders, or to an
|
|
12070
|
+
* override of one, which decides the whole gate no.
|
|
12071
|
+
*/
|
|
12072
|
+
const NeedStanding = Schema.Union([
|
|
12073
|
+
Schema.Struct({
|
|
12074
|
+
state: Schema.Literal("met"),
|
|
12075
|
+
by: Schema.Array(NeedYes).check(Schema.isMaxLength(maxGateDeciders))
|
|
12076
|
+
}),
|
|
12077
|
+
Schema.Struct({
|
|
12078
|
+
state: Schema.Literal("met"),
|
|
12079
|
+
as: Schema.Literals(["no checks", "on the tip"])
|
|
12080
|
+
}),
|
|
12081
|
+
Schema.Struct({
|
|
12082
|
+
state: Schema.Literal("waiting"),
|
|
12083
|
+
on: Schema.Array(NeedWait).check(Schema.isMaxLength(maxGateDeciders)),
|
|
12084
|
+
all: Schema.Boolean
|
|
12085
|
+
}),
|
|
12086
|
+
Schema.Struct({
|
|
12087
|
+
state: Schema.Literal("waiting"),
|
|
12088
|
+
for: Schema.Literal("checks read")
|
|
12089
|
+
}),
|
|
12090
|
+
Schema.Struct({
|
|
12091
|
+
state: Schema.Literal("refused"),
|
|
12092
|
+
decider: DeciderRef,
|
|
12093
|
+
by: PersonId
|
|
12094
|
+
})
|
|
12095
|
+
]);
|
|
12096
|
+
/** A version's need, with every place it came from, and how it stands once its gate is open. */
|
|
12097
|
+
const GateNeedView = Schema.Struct({
|
|
12098
|
+
...GateNeed.fields,
|
|
12099
|
+
standing: Schema.optionalKey(NeedStanding)
|
|
12100
|
+
});
|
|
12101
|
+
/**
|
|
11837
12102
|
* The version's gate decided again in place under `main`'s `.ref0/` now (Q7c): on which `main`
|
|
11838
12103
|
* and under its tree, `pending` until `main`'s gate answers, then `held` or `grew`; the needs
|
|
11839
12104
|
* it answered, joined to ref0's floor, absent while pending; what `main`'s gate read of the
|
|
@@ -11935,8 +12200,21 @@ const GateView = Schema.Struct({
|
|
|
11935
12200
|
state: GateState,
|
|
11936
12201
|
/** Why the gate failed; null otherwise. */
|
|
11937
12202
|
why: Schema.NullOr(Schema.String),
|
|
11938
|
-
/**
|
|
11939
|
-
|
|
12203
|
+
/**
|
|
12204
|
+
* None while pending; once answered, the floor's too, sorted as they're spelled, each with how
|
|
12205
|
+
* it stands once the version's gate is open.
|
|
12206
|
+
*/
|
|
12207
|
+
needs: Schema.Array(GateNeedView),
|
|
12208
|
+
/** The repo's owner, whose admins answer its admins' needs: at home, its person alone. */
|
|
12209
|
+
owner: OwnerId,
|
|
12210
|
+
/**
|
|
12211
|
+
* The names of the owner and of the people its needs' standings name, where the directory has
|
|
12212
|
+
* them.
|
|
12213
|
+
*/
|
|
12214
|
+
names: Schema.optionalKey(Schema.Array(Schema.Struct({
|
|
12215
|
+
owner: OwnerId,
|
|
12216
|
+
name: OwnerName
|
|
12217
|
+
})).check(Schema.isMaxLength(maxGateDeciders + 1))),
|
|
11940
12218
|
/** What the gate read of the change's trees, each read once, in order; none while pending. */
|
|
11941
12219
|
reads: GateReads,
|
|
11942
12220
|
/** The project gate revision the version was decided under; none for 0. */
|
|
@@ -14074,6 +14352,7 @@ const KnownEvent = Schema.Union([
|
|
|
14074
14352
|
ThreadListingChanged,
|
|
14075
14353
|
SessionStarted,
|
|
14076
14354
|
SessionEnded,
|
|
14355
|
+
IdentityTokenIssued,
|
|
14077
14356
|
MemberRoleChanged,
|
|
14078
14357
|
MemberRemoved,
|
|
14079
14358
|
InvitationSent,
|
|
@@ -14917,6 +15196,11 @@ var ApprovalSecret = class extends HttpApiMiddleware.Service()("ref0/contracts/A
|
|
|
14917
15196
|
* what to change. Any other part that fails its contract is answered with Effect's empty 400.
|
|
14918
15197
|
*/
|
|
14919
15198
|
var MachineNameRefusal = class extends HttpApiMiddleware.Service()("ref0/contracts/MachineNameRefusal", { error: CommandRefused }) {};
|
|
15199
|
+
/**
|
|
15200
|
+
* An identity token's request whose audience its contract refuses, missing or not an HTTPS
|
|
15201
|
+
* origin, answered as `IdentityAudienceRefused`, which never echoes what was sent.
|
|
15202
|
+
*/
|
|
15203
|
+
var IdentityAudienceRefusal = class extends HttpApiMiddleware.Service()("ref0/contracts/IdentityAudienceRefusal", { error: IdentityAudienceRefused }) {};
|
|
14920
15204
|
const idempotency = { "idempotency-key": RequestId };
|
|
14921
15205
|
const inProject = {
|
|
14922
15206
|
owner: OwnerRef,
|
|
@@ -15139,7 +15423,18 @@ var MeGroup = class extends HttpApiGroup.make("me").add(HttpApiEndpoint.get("get
|
|
|
15139
15423
|
UsageRangeRefused,
|
|
15140
15424
|
AuthorityUnavailable
|
|
15141
15425
|
]
|
|
15142
|
-
})
|
|
15426
|
+
}), HttpApiEndpoint.post("identityToken", identityTokenPath, {
|
|
15427
|
+
payload: IdentityTokenRequest,
|
|
15428
|
+
success: IssuedIdentityToken,
|
|
15429
|
+
error: [
|
|
15430
|
+
IdentityAudienceRefused,
|
|
15431
|
+
IdentityTokenNotReady,
|
|
15432
|
+
NotPermitted,
|
|
15433
|
+
SessionHasEnded,
|
|
15434
|
+
SlowDown,
|
|
15435
|
+
AuthorityUnavailable
|
|
15436
|
+
]
|
|
15437
|
+
}).middleware(IdentityAudienceRefusal)).middleware(Authorization) {};
|
|
15143
15438
|
/**
|
|
15144
15439
|
* A thread's endpoints, as one of a project's threads and an org thread take them alike, by
|
|
15145
15440
|
* where they are: `at` is a project's path parameters, or the owner's alone for its own scope.
|
|
@@ -16075,15 +16370,18 @@ const decisionEndpoints = (at) => {
|
|
|
16075
16370
|
HttpApiEndpoint.get("get", "/:decision", {
|
|
16076
16371
|
params: onDecision,
|
|
16077
16372
|
query: { wait: Schema.optionalKey(DecisionWait) },
|
|
16078
|
-
success:
|
|
16373
|
+
success: NamedDecision,
|
|
16079
16374
|
error: [...projectErrors, DecisionNotFound]
|
|
16080
16375
|
}),
|
|
16081
16376
|
HttpApiEndpoint.post("answer", "/:decision/answers", {
|
|
16082
16377
|
params: onDecision,
|
|
16083
16378
|
headers: idempotency,
|
|
16084
16379
|
payload: AnswerRequest,
|
|
16085
|
-
success:
|
|
16380
|
+
success: NamedDecision,
|
|
16086
16381
|
error: [
|
|
16382
|
+
ApprovalNeeded,
|
|
16383
|
+
CommandRefused,
|
|
16384
|
+
SlowDown,
|
|
16087
16385
|
...projectErrors,
|
|
16088
16386
|
DecisionNotFound,
|
|
16089
16387
|
AnswerRefused,
|
|
@@ -16898,6 +17196,15 @@ const ownSurfaces = {
|
|
|
16898
17196
|
cli: "meters",
|
|
16899
17197
|
mcp: null
|
|
16900
17198
|
},
|
|
17199
|
+
"me.identityToken": {
|
|
17200
|
+
action: "session:change",
|
|
17201
|
+
actors: "agent",
|
|
17202
|
+
target: "session",
|
|
17203
|
+
stepUp: "never",
|
|
17204
|
+
asks: "never",
|
|
17205
|
+
cli: "identity-token",
|
|
17206
|
+
mcp: null
|
|
17207
|
+
},
|
|
16901
17208
|
"threads.list": {
|
|
16902
17209
|
action: "project:read",
|
|
16903
17210
|
actors: "both",
|
|
@@ -18328,6 +18635,6 @@ const signOut = (origin) => Effect.gen(function* () {
|
|
|
18328
18635
|
yield* client.execute(HttpClientRequest.make(method)(path, { body: HttpBody.jsonUnsafe({}) }));
|
|
18329
18636
|
});
|
|
18330
18637
|
//#endregion
|
|
18331
|
-
export { AgentHandle, ApiOrigin, AttachmentFailed, AttachmentRequestView, ClientAccess, ClientGranted, ConnectionChanged, ConnectionKind, ConnectionName, ConsentProject, FoldersConnected, LiveTrackName, MachineConnected, OwnerName, OwnerTrackMessage, PasskeyAsserted, PasskeyCreated, PreviewUnavailable, ProjectName, ProjectTrackMessage, RepoName, RepoUrl, SecretHash, SentryOrg, SentryRegion, SentryToken, SignInDestination, ThreadId, ThreadStage, TypedApprovalCode, WorkflowPreview, WrittenProject, anonymousCredential, bearerCredential, browserCredential, commandLine, connectEndpoint, encodeSecret, fetchTransport, followApproval, hookTokenPrefix, hookUrl, isRef0Path, liveMessages, liveSocketUrl, newRequestId, projectParts, ref0Client, repoNameKey, settledOf, signOut, startGitHubSignIn, surfaceOf };
|
|
18638
|
+
export { AgentHandle, AnswerKey, ApiOrigin, AttachmentFailed, AttachmentRequestView, ClientAccess, ClientGranted, ConnectionChanged, ConnectionKind, ConnectionName, ConsentProject, FoldersConnected, LiveTrackName, MachineConnected, OwnerName, OwnerTrackMessage, PasskeyAsserted, PasskeyCreated, PreviewUnavailable, ProjectName, ProjectTrackMessage, RepoName, RepoUrl, SecretHash, SentryOrg, SentryRegion, SentryToken, SignInDestination, ThreadId, ThreadStage, TypedApprovalCode, WorkflowPreview, WrittenProject, anonymousCredential, bearerCredential, browserCredential, commandLine, connectEndpoint, encodeSecret, fetchTransport, followApproval, hookTokenPrefix, hookUrl, isRef0Path, liveMessages, liveSocketUrl, newRequestId, projectParts, ref0Client, repoNameKey, settledOf, signOut, startGitHubSignIn, surfaceOf, threadParts };
|
|
18332
18639
|
|
|
18333
18640
|
//# sourceMappingURL=client.mjs.map
|