@knkcs/contenthub-ui 0.1.0 → 0.3.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heads-dBmqNcOB.js","names":["CHECK_NOTE_MAX","CONTENT_SEARCH_MAX","CHANGE_SET_NAME_MAX","SOURCE_REFERENCE_MAX","BLOCK_REASON_NAME_MAX","ContentBlockedError","contentId","blockReasonId","ContentArchivedError","StatusTransitionRefusedError","input","StaleStatusError","currentStatus","ServiceUnavailableError","message","WithheldWorkError","ChangeSetClosedError","state","BlockReasonNameTakenError","takenName","ContentRefusedError","reasons","PublishRefusedError","blockers","StaleHeadError","CheckResultDeniedError","NameTakenError","RestrictionUnavailableError","GuardianModeRequiredError","feature","AccessDeniedError","CoversReleaseError","coveredReleaseIds","COLLECTION_NAME_MAX","REQUIRED_CHECK_NAME_MAX","MAX_BLUEPRINT_IDS","BLUEPRINT_ACCESSOR_MAX","InvalidInputError","DAY","localToday","pad","n","now","dated","entries","releaseInForceOn","day","last","inForceOnOrAfter","headsOf","out","chain","cs","b","sameHeads","keys","a","k"],"sources":["../src/client/contenthub-client.ts","../src/common/in-force.ts","../src/common/heads.ts"],"sourcesContent":["import type {\n\tBlockReason,\n\tBlueprintInfo,\n\tBlueprintPage,\n\tBlueprintReleaseInfo,\n\tChainPreview,\n\tChangeSet,\n\tChangeSetList,\n\tChangeSetSource,\n\tChangeSetState,\n\tCheckOutcome,\n\tCheckResult,\n\tCheckStanding,\n\tCollection,\n\tCollectionGrant,\n\tCompareBase,\n\tContent,\n\tContentAttributes,\n\tContentDetail,\n\tContentList,\n\tContentTimeline,\n\tContentView,\n\tCopyFrom,\n\tEdge,\n\tFieldResolution,\n\tOutdatedPin,\n\tPendingMerge,\n\tPlannedEnd,\n\tPlannedRelease,\n\tPreviewedContent,\n\tPublishBlocker,\n\tPublishOutcome,\n\tPublishReview,\n\tRecorderGrant,\n\tReferrerList,\n\tRequiredCheck,\n\tRequiredCheckInput,\n\tRequiredCheckRecorders,\n\tRevisionComparison,\n\tRevisionList,\n\tUpdateFromMainOutcome,\n\tValidityPeriod,\n} from \"../types\";\n\n/** The longest note on a Check Result, in characters (internal/changesets.MaxCheckNote). */\nexport const CHECK_NOTE_MAX = 2000;\n\n/** The longest Editor Search, in characters (ContentFilter.search). */\nexport const CONTENT_SEARCH_MAX = 200;\n\n/** The longest Change Set name, in characters (internal/changesets.MaxNameLength). */\nexport const CHANGE_SET_NAME_MAX = 200;\n\n/** The longest Source reference, in characters (internal/changesets.MaxReferenceLength). */\nexport const SOURCE_REFERENCE_MAX = 500;\n\n/**\n * The longest Block Reason name, in characters: the service's limit\n * (internal/workspaceconfig.MaxBlockReasonName), checked here too so a form\n * says so before it asks.\n */\nexport const BLOCK_REASON_NAME_MAX = 200;\n\n/** What `updateChangeSet` changes of a Change Set. */\nexport type ChangeSetUpdateField = \"name\" | \"source\";\n\n/**\n * Everything contenthub-ui's screens ask contenthub, and nothing else: the\n * port a host fills (ADR 0020). `createConnectContenthubClient` is the\n * production implementation; `@knkcs/contenthub-ui/testing` has a stub over\n * an in-memory workspace.\n *\n * Errors the screens act on arrive as the typed errors below, never as a\n * ConnectError the screen would have to pick details out of. Anything else\n * (no permission, the service down) arrives as it came.\n *\n * The workspace is never an argument: contenthub reads it from the caller's\n * token (contenthub ADR 0017), so a host cannot ask about another workspace by\n * mistake.\n */\nexport interface ContenthubClient {\n\t/** The workspace's Block Reasons, by name. */\n\tlistBlockReasons(): Promise<BlockReason[]>;\n\t/**\n\t * Adds a Block Reason. Rejects with `BlockReasonNameTakenError` when the\n\t * workspace already has one of that name, and `InvalidInputError` for a\n\t * name the service refuses (blank, too long, more than one line).\n\t */\n\tcreateBlockReason(input: { name: string }): Promise<BlockReason>;\n\t/** Renames a Block Reason; its id stays. Rejects as `createBlockReason` does. */\n\trenameBlockReason(input: { id: string; name: string }): Promise<BlockReason>;\n\t/** Removes a Block Reason. */\n\tdeleteBlockReason(input: { id: string }): Promise<void>;\n\n\t/**\n\t * Change Sets, newest first, without their Chains, dependencies or\n\t * Planned Releases. Each filter given must hold.\n\t */\n\tlistChangeSets(input?: {\n\t\tstate?: ChangeSetState;\n\t\t/** Only those this odon user is assigned to. */\n\t\tassigneeId?: string;\n\t\t/** Only those with a Chain on this Content. */\n\t\tcontentId?: string;\n\t\t/** At most 200; 50 when absent. */\n\t\tpageSize?: number;\n\t\tpageToken?: string;\n\t}): Promise<ChangeSetList>;\n\t/**\n\t * Opens a Change Set. Rejects with `InvalidInputError` for a name or\n\t * Source the service refuses.\n\t */\n\tcreateChangeSet(input: { name: string; source?: ChangeSetSource }): Promise<ChangeSet>;\n\t/** A Change Set with its Chains, their Branches' heads and its dependencies. */\n\tgetChangeSet(id: string): Promise<ChangeSet>;\n\t/**\n\t * Renames an open Change Set and corrects its Source, as `updateMask`\n\t * says: a field it doesn't name is left as it is, and a masked `source`\n\t * that is absent clears the Source. Rejects with `InvalidInputError` for\n\t * a name or Source the service refuses, and `ChangeSetClosedError` once\n\t * it is published or discarded: the Source freezes at Publish.\n\t */\n\tupdateChangeSet(input: {\n\t\tid: string;\n\t\tupdateMask: ChangeSetUpdateField[];\n\t\tname?: string;\n\t\tsource?: ChangeSetSource;\n\t\t/** Makes a retry safe (CONTEXT.md, Idempotency Key). */\n\t\tidempotencyKey?: string;\n\t}): Promise<ChangeSet>;\n\t/**\n\t * Moves the status label from `expectedStatus` (the status the caller\n\t * saw, \"\" for none) to `status`. Rejects with\n\t * `StatusTransitionRefusedError` when statushub refuses the move,\n\t * `StaleStatusError` when the status moved meanwhile,\n\t * `ChangeSetClosedError` when the Change Set is published or discarded,\n\t * and `ServiceUnavailableError` while statushub can't be reached.\n\t */\n\tsetChangeSetStatus(input: {\n\t\tid: string;\n\t\texpectedStatus: string;\n\t\tstatus: string;\n\t}): Promise<ChangeSet>;\n\t/** Replaces who is working on it: the whole new set of odon user ids. */\n\tsetChangeSetAssignees(input: { id: string; assigneeIds: string[] }): Promise<ChangeSet>;\n\t/**\n\t * Makes the Change Set depend on another open one. Rejects with\n\t * `InvalidInputError` for one that would close a cycle or is closed, and\n\t * `ChangeSetClosedError` when this Change Set itself is closed.\n\t */\n\taddDependency(input: { id: string; dependsOnId: string }): Promise<ChangeSet>;\n\t/** Undoes `addDependency` while the Change Set is open. */\n\tremoveDependency(input: { id: string; dependsOnId: string }): Promise<ChangeSet>;\n\t/**\n\t * Publish's dry run with `reviewedHeads` (Branch id to head Revision id):\n\t * every blocker a Publish with them would be refused with now, and the\n\t * Releases it would cut. Writes nothing. Rejects with `WithheldWorkError`\n\t * when Publish would, for a caller who can't see all of the Change Set.\n\t */\n\tvalidatePublish(input: {\n\t\tid: string;\n\t\treviewedHeads: Record<string, string>;\n\t}): Promise<PublishReview>;\n\t/**\n\t * Publishes the Change Set with exactly `reviewedHeads`: every Branch at\n\t * the head the caller reviewed. Rejects with `PublishRefusedError`\n\t * carrying every blocker when it is refused, `ChangeSetClosedError`\n\t * when it is closed (published with other heads, or discarded), and\n\t * `WithheldWorkError` when it holds work the caller can't see.\n\t */\n\tpublish(input: { id: string; reviewedHeads: Record<string, string> }): Promise<PublishOutcome>;\n\t/**\n\t * Merges what Main (and each dependency) gained since into every Chain\n\t * of the Change Set. A Branch whose merge has Conflicts, or fails its\n\t * Blueprint Release, is left with a Pending Merge, which the Branch\n\t * editor resolves. Rejects with `ChangeSetClosedError` when it is closed,\n\t * and, without `chainId`, `WithheldWorkError` when it holds work the\n\t * caller can't see.\n\t */\n\tupdateFromMain(input: {\n\t\tid: string;\n\t\t/** One of its Chains to update alone; every Chain when absent. */\n\t\tchainId?: string;\n\t\t/** Makes a retry safe (CONTEXT.md, Idempotency Key). */\n\t\tidempotencyKey?: string;\n\t}): Promise<UpdateFromMainOutcome>;\n\t/**\n\t * Closes the Change Set for good without publishing it. Rejects with\n\t * `ChangeSetClosedError` when it is closed already, and\n\t * `WithheldWorkError` when it holds work the caller can't see.\n\t */\n\tdiscardChangeSet(id: string): Promise<ChangeSet>;\n\t/**\n\t * Where every Required Check that applies to the Change Set stands: the\n\t * heads a result recorded now names, its results newest first, and\n\t * whether the latest is stale or clears it.\n\t */\n\tlistCheckResults(changeSetId: string): Promise<CheckStanding[]>;\n\t/**\n\t * Records a Check Result against `heads`, the heads the recorder saw.\n\t * Rejects with `StaleHeadError` when one of them moved,\n\t * `CheckResultDeniedError` when the caller may not record it (an\n\t * independent check's passed or waived from an author of what it\n\t * covers), `InvalidInputError` for what\n\t * the service refuses (a waiver without a note), and\n\t * `ChangeSetClosedError` when the Change Set is closed.\n\t */\n\trecordCheckResult(input: {\n\t\tchangeSetId: string;\n\t\trequiredCheckId: string;\n\t\theads: Record<string, string>;\n\t\toutcome: CheckOutcome;\n\t\tnote: string;\n\t}): Promise<CheckResult>;\n\n\t/** The workspace's Required Checks, by name. */\n\tlistRequiredChecks(): Promise<RequiredCheck[]>;\n\t/**\n\t * Declares a Required Check; it gates every open Change Set at once.\n\t * Rejects with `NameTakenError` when another check has the name, and\n\t * `InvalidInputError` for anything else the service refuses.\n\t */\n\tcreateRequiredCheck(input: RequiredCheckInput): Promise<RequiredCheck>;\n\t/** Replaces every field of a Required Check; its id stays. Rejects as create does. */\n\tupdateRequiredCheck(input: RequiredCheckInput & { id: string }): Promise<RequiredCheck>;\n\t/**\n\t * Removes a Required Check: it stops gating. Its results are kept and\n\t * count for nothing; its recorders' grants go with it. Rejects with\n\t * `ServiceUnavailableError` while Guardian doesn't take that, and nothing\n\t * is removed.\n\t */\n\tdeleteRequiredCheck(input: { id: string }): Promise<void>;\n\t/**\n\t * Who records a Required Check: every member until an admin narrows it\n\t * (ADR 0017's 2026-10-03 amendment). Admin only: rejects with\n\t * `AccessDeniedError` otherwise, and with `GuardianModeRequiredError` in\n\t * `authz.mode: workspace`, where every member records every check and\n\t * nothing narrows it.\n\t */\n\tlistRequiredCheckRecorders(requiredCheckId: string): Promise<RequiredCheckRecorders>;\n\t/**\n\t * Makes a member, or every member, a recorder of a Required Check. The\n\t * caller may grant themselves: an admin records a check only when\n\t * granted (break-glass, announced like any grant). Rejects as\n\t * `listRequiredCheckRecorders` does, with `InvalidInputError` for a\n\t * grantee who is not a member, and `ServiceUnavailableError` while\n\t * Guardian doesn't take the grant.\n\t */\n\tgrantRequiredCheckRecorder(input: {\n\t\trequiredCheckId: string;\n\t\trecorder: RecorderGrant;\n\t}): Promise<void>;\n\t/**\n\t * Takes recorder from a person, or from every member, which narrows the\n\t * check to the people granted by name. Rejects as grant does.\n\t */\n\trevokeRequiredCheckRecorder(input: {\n\t\trequiredCheckId: string;\n\t\trecorder: RecorderGrant;\n\t}): Promise<void>;\n\n\t/** Every Collection of the workspace, by name, then id: a tree by `parentId`. */\n\tlistCollections(): Promise<Collection[]>;\n\t/**\n\t * Creates a Collection at the root or under `parentId`. Rejects with\n\t * `NameTakenError` for a sibling of the same name, `InvalidInputError` for\n\t * a name the service refuses, and `RestrictionUnavailableError` for a\n\t * restricted one in workspace mode.\n\t */\n\tcreateCollection(input: {\n\t\tname: string;\n\t\tparentId?: string;\n\t\trestricted?: boolean;\n\t}): Promise<Collection>;\n\t/** Renames a Collection, keeping its place and filing. Rejects as create does. */\n\trenameCollection(input: { id: string; name: string }): Promise<Collection>;\n\t/**\n\t * Moves a Collection, with everything under it, under `parentId` (\"\" for\n\t * the root). Rejects with `InvalidInputError` for a move under itself, and\n\t * `NameTakenError` for a sibling of the same name there, whose\n\t * `takenName` is \"\": the request carries no name.\n\t */\n\tmoveCollection(input: { id: string; parentId: string }): Promise<Collection>;\n\t/**\n\t * Removes a Collection and unfiles its Content, answering the Content it\n\t * unfiled. Rejects with `InvalidInputError` while Collections sit under it.\n\t */\n\tremoveCollection(input: { id: string }): Promise<string[]>;\n\t/**\n\t * Restricts a Collection (the caller becomes its owner), or opens it\n\t * again, which discloses its Content to every viewer and so needs\n\t * `acknowledgeDisclosure`; opening it clears its grants. Rejects with\n\t * `RestrictionUnavailableError` in workspace mode, and\n\t * `InvalidInputError` for an unacknowledged disclosure.\n\t */\n\tsetCollectionRestricted(input: {\n\t\tid: string;\n\t\trestricted: boolean;\n\t\tacknowledgeDisclosure?: boolean;\n\t}): Promise<Collection>;\n\t/**\n\t * Who is granted on a Restricted Collection, its owner included. Rejects\n\t * with `AccessDeniedError` unless the caller is its owner or an admin, and\n\t * `RestrictionUnavailableError` in workspace mode.\n\t */\n\tlistCollectionGrants(collectionId: string): Promise<CollectionGrant[]>;\n\t/**\n\t * Grants a member viewer or editor on a Restricted Collection, replacing\n\t * what they held. The caller may grant themselves (break-glass, announced\n\t * like any grant). Rejects as `listCollectionGrants` does, and with\n\t * `InvalidInputError` for a grantee who is not a member or an open\n\t * Collection.\n\t */\n\tgrantCollectionAccess(input: {\n\t\tcollectionId: string;\n\t\tuserId: string;\n\t\tlevel: \"viewer\" | \"editor\";\n\t}): Promise<void>;\n\t/** Takes a person's grant on a Restricted Collection. Rejects as grant does. */\n\trevokeCollectionAccess(input: { collectionId: string; userId: string }): Promise<void>;\n\t/**\n\t * Content in one view, ordered by id (then Branch, for a search), each\n\t * filter given holding. Rejects with `InvalidInputError` for a search in\n\t * the In Force view, which Editor Search never covers (ADR 0019), and for\n\t * a search the service refuses.\n\t */\n\tlistContents(input?: {\n\t\t/** Main when absent. */\n\t\tview?: ContentView;\n\t\t/**\n\t\t * Only Content filed directly in this Collection, not in Collections\n\t\t * under it.\n\t\t */\n\t\tcollectionId?: string;\n\t\t/** Editor Search: a name, number or phrase, letter for letter but ignoring case. */\n\t\tsearch?: string;\n\t\t/**\n\t\t * Only Content of one of these Blueprints, filtered by the service so\n\t\t * that every page but the last is full; empty or absent for every\n\t\t * Blueprint. At most 100.\n\t\t */\n\t\tblueprintIds?: string[];\n\t\t/** Only Content this user maintains: one of its assignees. */\n\t\tassigneeId?: string;\n\t\t/** At most 200; 50 when absent. */\n\t\tpageSize?: number;\n\t\tpageToken?: string;\n\t}): Promise<ContentList>;\n\t/**\n\t * A page of the workspace's content Blueprints Content can be made from:\n\t * not archived, with at least one Release, whose accessor or name holds\n\t * `query`. contenthub asks blueprinthub as the caller (#238). Rejects\n\t * with `ServiceUnavailableError` while blueprinthub gives no answer.\n\t */\n\tsearchBlueprints(input: {\n\t\tquery: string;\n\t\tpageToken?: string;\n\t\tsignal?: AbortSignal;\n\t}): Promise<BlueprintPage>;\n\t/**\n\t * Every Release of a Blueprint, newest first, each with contenthub's\n\t * answer: `refusals` is empty when Content can pin it. Empty for a\n\t * Blueprint the workspace doesn't have. Rejects with\n\t * `ServiceUnavailableError` while blueprinthub gives no answer.\n\t */\n\tlistBlueprintReleases(blueprintId: string): Promise<BlueprintReleaseInfo[]>;\n\t/**\n\t * Names the Blueprints of these ids, archived ones and ones without a\n\t * Release included, so existing Content stays readable after its\n\t * Blueprint is retired (#241). An unknown id, or one of another\n\t * workspace, is left out. At most `MAX_BLUEPRINT_IDS`. Rejects with\n\t * `ServiceUnavailableError` while blueprinthub gives no answer.\n\t */\n\tgetBlueprints(ids: string[]): Promise<BlueprintInfo[]>;\n\t/**\n\t * Creates a Content in an open Change Set, pinning a Blueprint Release,\n\t * with empty data: its one Chain has one Branch, opened in the Branch\n\t * editor. Rejects with `ChangeSetClosedError` for a closed Change Set,\n\t * `ContentRefusedError` for a Release contenthub can't load or empty data\n\t * the Release refuses (a required field), and `InvalidInputError` for\n\t * anything else the service refuses.\n\t */\n\tcreateContent(input: {\n\t\tchangeSetId: string;\n\t\t/** May be \"\" with `copyFrom`, to pin what the source pins. */\n\t\tblueprintReleaseId: string;\n\t\t/** Duplicate: the new Content's first Revision takes this source's data. */\n\t\tcopyFrom?: CopyFrom;\n\t}): Promise<Content>;\n\t/**\n\t * Saves a new Revision on a Branch of an open Change Set, on top of\n\t * `expectedHeadId`, the head the editor loaded (ADR 0003). With\n\t * `fieldMask` the save is partial: each top-level field it names takes\n\t * its value in `data`, or is removed when `data` doesn't hold it, and\n\t * every other field is carried over from the head. Answers the Content\n\t * as read in the Change Set afterwards.\n\t *\n\t * Rejects with `StaleHeadError` when the head moved (nothing is written,\n\t * and nothing is merged: ADR 0020), `ContentRefusedError` with one reason\n\t * per Violation the data breaks, `ContentBlockedError` or\n\t * `ContentArchivedError` for Content closed to the caller,\n\t * `ChangeSetClosedError` for a closed Change Set, and `InvalidInputError`\n\t * for anything else the service refuses.\n\t */\n\tsaveRevision(input: {\n\t\t/** The Branch's Change Set, which a closed refusal names. */\n\t\tchangeSetId: string;\n\t\tbranchId: string;\n\t\texpectedHeadId: string;\n\t\tdata: Record<string, unknown>;\n\t\t/** Top-level field accessors; absent saves `data` as the whole Revision. */\n\t\tfieldMask?: string[];\n\t\t/**\n\t\t * Makes a retry safe (CONTEXT.md, Idempotency Key): sent again with\n\t\t * the same request, it answers the first save and writes nothing.\n\t\t */\n\t\tidempotencyKey?: string;\n\t}): Promise<Content>;\n\n\t/**\n\t * One Content with its Blueprint Release and attributes: on Main, or\n\t * inside `changeSetId`. Content born in an open Change Set exists only\n\t * there, so read anywhere else it is a NotFound ConnectError.\n\t */\n\tgetContent(input: { id: string; changeSetId?: string }): Promise<ContentDetail>;\n\t/** Its Timeline, with the Planned Releases of open Change Sets beside it. */\n\tgetTimeline(contentId: string): Promise<ContentTimeline>;\n\t/**\n\t * Revisions, newest first: every one of a published Content, or those of\n\t * one Branch (the only way to list those of Content born in an open\n\t * Change Set).\n\t */\n\tlistRevisions(input: {\n\t\ttarget: { contentId: string } | { branchId: string };\n\t\tpageSize?: number;\n\t\tpageToken?: string;\n\t}): Promise<RevisionList>;\n\t/** How `revisionId` differs from a base, field by field. */\n\tcompare(input: { revisionId: string; base: CompareBase }): Promise<RevisionComparison>;\n\t/** The outgoing edges of one Revision, its own only. */\n\tlistReferences(input: { contentId: string; revisionId: string }): Promise<Edge[]>;\n\t/**\n\t * One page of the edges pointing at a Content from Releases In Force\n\t * today and, asked, open Branch heads: Releases first, then Change Sets.\n\t */\n\tlistReferrers(input: {\n\t\tcontentId: string;\n\t\tincludeOpenChangeSets?: boolean;\n\t\t/** 100 when absent; above 1000 reads as 1000. */\n\t\tpageSize?: number;\n\t\tpageToken?: string;\n\t}): Promise<ReferrerList>;\n\t/** The pinned edges of a Branch head or a Revision that are outdated today. */\n\tlistOutdatedPins(input: { branchId: string } | { revisionId: string }): Promise<OutdatedPin[]>;\n\n\t/** Files a Content in exactly these Collections: no save, no Revision (ADR 0015). Answers its Collections. */\n\tsetContentCollections(input: { contentId: string; collectionIds: string[] }): Promise<string[]>;\n\t/** Replaces who maintains a Content: no save, no Revision. */\n\tsetContentAssignees(input: {\n\t\tcontentId: string;\n\t\tassigneeIds: string[];\n\t}): Promise<ContentAttributes>;\n\t/** Blocks a Content, replacing any Block it has. */\n\tblockContent(input: {\n\t\tcontentId: string;\n\t\tblockReasonId: string;\n\t\tallowedUserIds: string[];\n\t}): Promise<ContentAttributes>;\n\tunblockContent(contentId: string): Promise<ContentAttributes>;\n\t/**\n\t * Archives a published Content with no Release In Force today or later.\n\t * Rejects with `InvalidInputError` for any other, with the service's reason.\n\t */\n\tarchiveContent(contentId: string): Promise<ContentAttributes>;\n\tunarchiveContent(contentId: string): Promise<ContentAttributes>;\n\n\t/**\n\t * Starts a Chain on a published Content, in `changeSetId` or in a new\n\t * Change Set named `changeSetName` (after the Content when empty).\n\t * Answers the Change Set and the Content as read on the Branch to edit.\n\t * Rejects with `ContentBlockedError`, `ContentArchivedError`,\n\t * `ChangeSetClosedError`, and `InvalidInputError` for anything else the\n\t * service refuses (a missing or needless effective date).\n\t */\n\tstartEditing(input: {\n\t\tcontentId: string;\n\t\tchangeSetId?: string;\n\t\t/** YYYY-MM-DD: required for Dated Content, refused for undated. */\n\t\teffectiveOn?: string;\n\t\tchangeSetName?: string;\n\t}): Promise<{ changeSet: ChangeSet; content: Content }>;\n\t/** What a Chain on Dated Content, effective on a date, would fork from and meet. */\n\tpreviewChain(input: {\n\t\tchangeSetId: string;\n\t\tcontentId: string;\n\t\teffectiveOn: string;\n\t\t/** The period to meet the Content's Releases with; from `effectiveOn`, open, when absent. */\n\t\tvalidityPeriod?: ValidityPeriod;\n\t}): Promise<ChainPreview>;\n\t/**\n\t * Plans the Release Publish will cut of an editorial Branch's head, with\n\t * its Validity Period (required for Dated Content, refused for undated)\n\t * and Release Spec values. Rejects with `ContentRefusedError` for Release\n\t * Spec values the Blueprint Release refuses, `CoversReleaseError` when\n\t * the period would cover a Release entirely, and as any edit does.\n\t */\n\tplanRelease(input: {\n\t\tchangeSetId: string;\n\t\tbranchId: string;\n\t\tvalidityPeriod?: ValidityPeriod;\n\t\treleaseSpec?: Record<string, unknown>;\n\t\tsupersedesReleaseIds?: string[];\n\t\tidempotencyKey?: string;\n\t}): Promise<PlannedRelease>;\n\t/**\n\t * Changes a Planned Release: each part given replaces what it had, each\n\t * absent keeps it. The Change Set's proposals are derived again. Rejects\n\t * as `planRelease` does, and with `InvalidInputError` for a proposal.\n\t */\n\tupdatePlannedRelease(input: {\n\t\tchangeSetId: string;\n\t\tplannedReleaseId: string;\n\t\tvalidityPeriod?: ValidityPeriod;\n\t\treleaseSpec?: Record<string, unknown>;\n\t\tsupersedesReleaseIds?: string[];\n\t\tidempotencyKey?: string;\n\t}): Promise<PlannedRelease>;\n\t/**\n\t * Adds an editorial Branch to a Chain on Dated Content, for a later\n\t * date. Answers the Change Set and the new Branch's id. Rejects with\n\t * `InvalidInputError` for a date not after the Chain's last editorial\n\t * Branch's, or a Chain without dates.\n\t */\n\tappendBranch(input: {\n\t\tchangeSetId: string;\n\t\tchainId: string;\n\t\teffectiveOn: string;\n\t\tidempotencyKey?: string;\n\t}): Promise<{ changeSet: ChangeSet; branchId: string }>;\n\t/**\n\t * Removes a Chain from an open Change Set with its Planned Releases; its\n\t * Revisions stay in history. Rejects with `InvalidInputError` for the\n\t * Chain of Content born in the Change Set.\n\t */\n\tdropChain(input: {\n\t\tchangeSetId: string;\n\t\tchainId: string;\n\t\tidempotencyKey?: string;\n\t}): Promise<ChangeSet>;\n\t/** The Pending Merge on a Branch, with what its resolution decides; null for none. */\n\tgetPendingMerge(branchId: string): Promise<PendingMerge | null>;\n\t/**\n\t * Resolves the Pending Merge on a Branch field by field, as a merge\n\t * Revision that becomes its head. Rejects with `StaleHeadError` when the\n\t * head moved, `ContentRefusedError` when the result fails the Blueprint\n\t * Release, and `InvalidInputError` for a field undecided or a Branch\n\t * without a Pending Merge.\n\t */\n\tresolveMerge(input: {\n\t\tchangeSetId: string;\n\t\tbranchId: string;\n\t\texpectedHeadId: string;\n\t\tresolutions: FieldResolution[];\n\t\tidempotencyKey?: string;\n\t}): Promise<Content>;\n\t/** Drops the Pending Merge on a Branch, which stays behind its base. */\n\tabortMerge(input: {\n\t\tchangeSetId: string;\n\t\tbranchId: string;\n\t\tidempotencyKey?: string;\n\t}): Promise<void>;\n\t/**\n\t * Preview: the Content as In Force on `validOn` (today when absent) if\n\t * the open Change Set were published now (ReleaseService's\n\t * preview_change_set); null when nothing is In Force then.\n\t */\n\tpreviewInForce(input: {\n\t\tcontentId: string;\n\t\tchangeSetId: string;\n\t\tvalidOn?: string;\n\t}): Promise<PreviewedContent | null>;\n\t/** Plans a Repeal of Dated Content ending on `lastDay`. */\n\tplanRepeal(input: {\n\t\tchangeSetId: string;\n\t\tcontentId: string;\n\t\tlastDay: string;\n\t}): Promise<PlannedEnd>;\n\t/** Plans a Withdrawal of undated Content. */\n\tplanWithdrawal(input: { changeSetId: string; contentId: string }): Promise<PlannedEnd>;\n}\n\n/** The Content is blocked, and its Block doesn't allow the caller. */\nexport class ContentBlockedError extends Error {\n\treadonly contentId: string;\n\treadonly blockReasonId: string;\n\tconstructor(contentId: string, blockReasonId: string) {\n\t\tsuper(`Content ${contentId} is blocked`);\n\t\tthis.name = \"ContentBlockedError\";\n\t\tthis.contentId = contentId;\n\t\tthis.blockReasonId = blockReasonId;\n\t}\n}\n\n/** The Content is Archived: unarchive it before editing it. */\nexport class ContentArchivedError extends Error {\n\treadonly contentId: string;\n\tconstructor(contentId: string) {\n\t\tsuper(`Content ${contentId} is archived`);\n\t\tthis.name = \"ContentArchivedError\";\n\t\tthis.contentId = contentId;\n\t}\n}\n\n/** statushub refused a status move: its reason is fit to show. */\nexport class StatusTransitionRefusedError extends Error {\n\treadonly fromStatus: string;\n\treadonly toStatus: string;\n\t/** statushub's reason, as it gave it. */\n\treadonly reason: string;\n\t/** A guarded move, which this caller may not make. */\n\treadonly requiresPermission: boolean;\n\tconstructor(input: {\n\t\tfromStatus: string;\n\t\ttoStatus: string;\n\t\treason: string;\n\t\trequiresPermission: boolean;\n\t}) {\n\t\tsuper(input.reason || `the move from \"${input.fromStatus}\" to \"${input.toStatus}\" was refused`);\n\t\tthis.name = \"StatusTransitionRefusedError\";\n\t\tthis.fromStatus = input.fromStatus;\n\t\tthis.toStatus = input.toStatus;\n\t\tthis.reason = input.reason;\n\t\tthis.requiresPermission = input.requiresPermission;\n\t}\n}\n\n/** The status moved since the caller saw it: choose again from `currentStatus`. */\nexport class StaleStatusError extends Error {\n\t/** \"\" for an unknown status. */\n\treadonly currentStatus: string;\n\tconstructor(currentStatus: string) {\n\t\tsuper(`the status is now \"${currentStatus}\"`);\n\t\tthis.name = \"StaleStatusError\";\n\t\tthis.currentStatus = currentStatus;\n\t}\n}\n\n/** A service the call needs can't be reached now: retry it unchanged. */\nexport class ServiceUnavailableError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"ServiceUnavailableError\";\n\t}\n}\n\n/**\n * The Change Set holds work the caller can't see: Content filed in a\n * Restricted Collection they aren't granted on (ADR 0017). Publishing,\n * discarding or updating all of it is refused, naming no Content. Read from\n * the refusal's typed WithheldWork detail, not its text.\n */\nexport class WithheldWorkError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"WithheldWorkError\";\n\t}\n}\n\n/** The Change Set is published or discarded, and closed for good. */\nexport class ChangeSetClosedError extends Error {\n\treadonly state: ChangeSetState;\n\tconstructor(state: ChangeSetState) {\n\t\tsuper(`the Change Set is ${state}`);\n\t\tthis.name = \"ChangeSetClosedError\";\n\t\tthis.state = state;\n\t}\n}\n\n/** Another Block Reason of the workspace already has this name. */\nexport class BlockReasonNameTakenError extends Error {\n\t/** The name asked for, which another Block Reason has. */\n\treadonly takenName: string;\n\tconstructor(takenName: string) {\n\t\tsuper(`a Block Reason named \"${takenName}\" already exists`);\n\t\tthis.name = \"BlockReasonNameTakenError\";\n\t\tthis.takenName = takenName;\n\t}\n}\n\n/** One reason contenthub refused a write, as the rule's owner gave it. */\nexport interface RefusalReason {\n\t/** Whose rule: \"fieldkit\", \"knkeditor\", \"format\" or \"contenthub\". */\n\tsource: string;\n\t/** The rule's own code, such as fieldkit's \"required\". */\n\tcode: string;\n\t/** A /-separated location, such as \"/title\"; \"\" for the whole. */\n\tpath: string;\n}\n\n/**\n * contenthub refused a Revision's data, a new Content's first or a save's:\n * it breaks the Blueprint Release's rules, or the Release can't be loaded.\n * `reasons` names each, as its owner gave it.\n */\nexport class ContentRefusedError extends Error {\n\treadonly reasons: RefusalReason[];\n\tconstructor(message: string, reasons: RefusalReason[]) {\n\t\tsuper(message);\n\t\tthis.name = \"ContentRefusedError\";\n\t\tthis.reasons = reasons;\n\t}\n}\n\n/**\n * Publish was refused: nothing was written. `blockers` names every reason\n * at once, so the editor fixes them in one pass (ADR 0015).\n */\nexport class PublishRefusedError extends Error {\n\treadonly blockers: PublishBlocker[];\n\tconstructor(blockers: PublishBlocker[]) {\n\t\tsuper(`Publish was refused for ${blockers.length} reason(s)`);\n\t\tthis.name = \"PublishRefusedError\";\n\t\tthis.blockers = blockers;\n\t}\n}\n\n/** A head the call named has moved since: read again and retry on `currentHeadId`. */\nexport class StaleHeadError extends Error {\n\treadonly contentId: string;\n\t/** \"\" for a Branch-less Planned Release's Revision. */\n\treadonly branchId: string;\n\treadonly expectedHeadId: string;\n\treadonly currentHeadId: string;\n\tconstructor(input: {\n\t\tcontentId: string;\n\t\tbranchId: string;\n\t\texpectedHeadId: string;\n\t\tcurrentHeadId: string;\n\t}) {\n\t\tsuper(`the head moved from ${input.expectedHeadId} to ${input.currentHeadId}`);\n\t\tthis.name = \"StaleHeadError\";\n\t\tthis.contentId = input.contentId;\n\t\tthis.branchId = input.branchId;\n\t\tthis.expectedHeadId = input.expectedHeadId;\n\t\tthis.currentHeadId = input.currentHeadId;\n\t}\n}\n\n/**\n * The caller may not record this result; `message` is the service's reason.\n * Mostly an independent Required Check's passed or waived from someone who\n * authored what it covers (ADR 0014), who may record failed only; also a\n * caller without the right to record the check at all.\n */\nexport class CheckResultDeniedError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"CheckResultDeniedError\";\n\t}\n}\n\n/**\n * Another Required Check, or a sibling Collection, already has this name.\n * The service's refusal carries no detail; the client knows what it sent.\n */\nexport class NameTakenError extends Error {\n\t/** The name asked for, trimmed. */\n\treadonly takenName: string;\n\tconstructor(takenName: string) {\n\t\tsuper(`\"${takenName}\" is taken`);\n\t\tthis.name = \"NameTakenError\";\n\t\tthis.takenName = takenName;\n\t}\n}\n\n/**\n * Restricted Collections need `authz.mode: guardian`: in workspace mode\n * nothing could enforce a restriction, so contenthub refuses every\n * restriction and grant (ADR 0017). No RPC says which mode runs, so the\n * screens learn it from this refusal, read from its GuardianModeRequired\n * detail (feature \"collection_restriction\"), not its text.\n */\nexport class RestrictionUnavailableError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"RestrictionUnavailableError\";\n\t}\n}\n\n/**\n * What was asked needs `authz.mode: guardian`; this contenthub runs in\n * workspace mode (ADR 0017). Read from the refusal's typed\n * GuardianModeRequired detail, not its text. `feature` names what was\n * refused: \"required_check_recorders\" for narrowing who records a check,\n * where every member records every check. Collection restriction's feature\n * comes as `RestrictionUnavailableError` instead.\n */\nexport class GuardianModeRequiredError extends Error {\n\treadonly feature: string;\n\tconstructor(feature: string, message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"GuardianModeRequiredError\";\n\t\tthis.feature = feature;\n\t}\n}\n\n/** The caller may not do this; `message` is the service's reason. */\nexport class AccessDeniedError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"AccessDeniedError\";\n\t}\n}\n\n/**\n * A plan's Validity Period would cover these Releases of its Content\n * entirely: nothing was planned. Supersede them, or change the dates.\n */\nexport class CoversReleaseError extends Error {\n\treadonly contentId: string;\n\treadonly coveredReleaseIds: string[];\n\tconstructor(contentId: string, coveredReleaseIds: string[]) {\n\t\tsuper(`the Validity Period covers ${coveredReleaseIds.join(\", \")} entirely`);\n\t\tthis.name = \"CoversReleaseError\";\n\t\tthis.contentId = contentId;\n\t\tthis.coveredReleaseIds = coveredReleaseIds;\n\t}\n}\n\n/** The longest Collection name, in characters (internal/collections.MaxNameLength). */\nexport const COLLECTION_NAME_MAX = 200;\n\n/** The longest Required Check name, in characters (internal/workspaceconfig.MaxRequiredCheckName). */\nexport const REQUIRED_CHECK_NAME_MAX = 200;\n\n/** The most ids one `getBlueprints` takes (internal/blueprintcatalog.MaxBlueprintIDs). */\nexport const MAX_BLUEPRINT_IDS = 1000;\n\n/** The longest Blueprint accessor a check names (internal/workspaceconfig.MaxBlueprintAccessor). */\nexport const BLUEPRINT_ACCESSOR_MAX = 200;\n\n/** The service refused a value; `message` is its guidance, fit to show. */\nexport class InvalidInputError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"InvalidInputError\";\n\t}\n}\n","import type { TimelineEntry } from \"../types\";\n\n/** A day as the service spells it: YYYY-MM-DD. */\nexport const DAY = /^\\d{4}-\\d{2}-\\d{2}$/;\n\n/**\n * Today as YYYY-MM-DD in the browser's time zone. The workspace's own time\n * zone decides In Force on the service; the page only uses this to choose\n * what to offer, and the service has the last word.\n */\nexport function localToday(now: Date = new Date()): string {\n\tconst pad = (n: number) => String(n).padStart(2, \"0\");\n\treturn `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;\n}\n\n/** Whether the Timeline is a Dated Content's: its Releases carry Validity Periods. */\nfunction dated(entries: TimelineEntry[]): boolean {\n\treturn entries.some((e) => e.validityPeriod);\n}\n\n/**\n * The Release In Force on `day`, as the Timeline known now gives it: for\n * Dated Content the one whose Validity Period covers the day, for undated\n * Content the latest one, unless a Withdrawal ended its force. Undefined in\n * a gap, before the first Release, or for Content never published.\n */\nexport function releaseInForceOn(entries: TimelineEntry[], day: string): TimelineEntry | undefined {\n\tif (dated(entries)) {\n\t\treturn entries.find(\n\t\t\t(e) =>\n\t\t\t\te.validityPeriod &&\n\t\t\t\te.validityPeriod.firstDay <= day &&\n\t\t\t\t(e.validityPeriod.lastDay === \"\" || day <= e.validityPeriod.lastDay),\n\t\t);\n\t}\n\tconst last = entries.at(-1);\n\treturn last && last.kind !== \"withdrawal\" ? last : undefined;\n}\n\n/**\n * Whether any Release is In Force on `day` or later: what ArchiveContent\n * refuses (ADR 0015), since archiving a live law would hide it from the\n * editors who maintain it. A Repeal is In Force up to its last day.\n */\nexport function inForceOnOrAfter(entries: TimelineEntry[], day: string): boolean {\n\tif (dated(entries)) {\n\t\treturn entries.some(\n\t\t\t(e) =>\n\t\t\t\te.validityPeriod && (e.validityPeriod.lastDay === \"\" || e.validityPeriod.lastDay >= day),\n\t\t);\n\t}\n\treturn releaseInForceOn(entries, day) !== undefined;\n}\n","import type { ChangeSet } from \"../types\";\n\n/**\n * Every Branch of a Change Set at its head, Branch id to Revision id: the\n * heads a Publish reviews, and that `reviewed_heads` must name exactly.\n */\nexport function headsOf(cs: ChangeSet): Record<string, string> {\n\tconst out: Record<string, string> = {};\n\tfor (const chain of cs.chains) {\n\t\tfor (const b of chain.branches) out[b.id] = b.headRevisionId;\n\t}\n\treturn out;\n}\n\n/** The same heads, Branch for Branch. */\nexport function sameHeads(a: Record<string, string>, b: Record<string, string>): boolean {\n\tconst keys = Object.keys(a);\n\treturn keys.length === Object.keys(b).length && keys.every((k) => b[k] === a[k]);\n}\n"],"mappings":";AA6CA,IAAaA,IAAiB,KAGjBC,IAAqB,KAGrBC,IAAsB,KAGtBC,IAAuB,KAOvBC,IAAwB,KAmhBxBC,IAAb,cAAyC,MAAM;CAC9C;CACA;CACA,YAAY,GAAmB,GAAuB;EAIrD,AAHA,MAAM,WAAWC,EAAU,YAAY,GACvC,KAAK,OAAO,uBACZ,KAAK,YAAYA,GACjB,KAAK,gBAAgBC;CACtB;AACD,GAGaC,IAAb,cAA0C,MAAM;CAC/C;CACA,YAAY,GAAmB;EAG9B,AAFA,MAAM,WAAWF,EAAU,aAAa,GACxC,KAAK,OAAO,wBACZ,KAAK,YAAYA;CAClB;AACD,GAGaG,IAAb,cAAkD,MAAM;CACvD;CACA;CAEA;CAEA;CACA,YAAY,GAKT;EAMF,AALA,MAAMC,EAAM,UAAU,kBAAkBA,EAAM,WAAW,QAAQA,EAAM,SAAS,cAAc,GAC9F,KAAK,OAAO,gCACZ,KAAK,aAAaA,EAAM,YACxB,KAAK,WAAWA,EAAM,UACtB,KAAK,SAASA,EAAM,QACpB,KAAK,qBAAqBA,EAAM;CACjC;AACD,GAGaC,IAAb,cAAsC,MAAM;CAE3C;CACA,YAAY,GAAuB;EAGlC,AAFA,MAAM,sBAAsBC,EAAc,EAAE,GAC5C,KAAK,OAAO,oBACZ,KAAK,gBAAgBA;CACtB;AACD,GAGaC,IAAb,cAA6C,MAAM;CAClD,YAAY,GAAiB;EAE5B,AADA,MAAMC,CAAO,GACb,KAAK,OAAO;CACb;AACD,GAQaC,IAAb,cAAuC,MAAM;CAC5C,YAAY,GAAiB;EAE5B,AADA,MAAMD,CAAO,GACb,KAAK,OAAO;CACb;AACD,GAGaE,IAAb,cAA0C,MAAM;CAC/C;CACA,YAAY,GAAuB;EAGlC,AAFA,MAAM,qBAAqBC,GAAO,GAClC,KAAK,OAAO,wBACZ,KAAK,QAAQA;CACd;AACD,GAGaC,IAAb,cAA+C,MAAM;CAEpD;CACA,YAAY,GAAmB;EAG9B,AAFA,MAAM,yBAAyBC,EAAU,iBAAiB,GAC1D,KAAK,OAAO,6BACZ,KAAK,YAAYA;CAClB;AACD,GAiBaC,IAAb,cAAyC,MAAM;CAC9C;CACA,YAAY,GAAiB,GAA0B;EAGtD,AAFA,MAAMN,CAAO,GACb,KAAK,OAAO,uBACZ,KAAK,UAAUO;CAChB;AACD,GAMaC,IAAb,cAAyC,MAAM;CAC9C;CACA,YAAY,GAA4B;EAGvC,AAFA,MAAM,2BAA2BC,EAAS,OAAO,WAAW,GAC5D,KAAK,OAAO,uBACZ,KAAK,WAAWA;CACjB;AACD,GAGaC,IAAb,cAAoC,MAAM;CACzC;CAEA;CACA;CACA;CACA,YAAY,GAKT;EAMF,AALA,MAAM,uBAAuBd,EAAM,eAAe,MAAMA,EAAM,eAAe,GAC7E,KAAK,OAAO,kBACZ,KAAK,YAAYA,EAAM,WACvB,KAAK,WAAWA,EAAM,UACtB,KAAK,iBAAiBA,EAAM,gBAC5B,KAAK,gBAAgBA,EAAM;CAC5B;AACD,GAQae,IAAb,cAA4C,MAAM;CACjD,YAAY,GAAiB;EAE5B,AADA,MAAMX,CAAO,GACb,KAAK,OAAO;CACb;AACD,GAMaY,IAAb,cAAoC,MAAM;CAEzC;CACA,YAAY,GAAmB;EAG9B,AAFA,MAAM,IAAIP,EAAU,WAAW,GAC/B,KAAK,OAAO,kBACZ,KAAK,YAAYA;CAClB;AACD,GASaQ,IAAb,cAAiD,MAAM;CACtD,YAAY,GAAiB;EAE5B,AADA,MAAMb,CAAO,GACb,KAAK,OAAO;CACb;AACD,GAUac,IAAb,cAA+C,MAAM;CACpD;CACA,YAAY,GAAiB,GAAiB;EAG7C,AAFA,MAAMd,CAAO,GACb,KAAK,OAAO,6BACZ,KAAK,UAAUe;CAChB;AACD,GAGaC,IAAb,cAAuC,MAAM;CAC5C,YAAY,GAAiB;EAE5B,AADA,MAAMhB,CAAO,GACb,KAAK,OAAO;CACb;AACD,GAMaiB,IAAb,cAAwC,MAAM;CAC7C;CACA;CACA,YAAY,GAAmB,GAA6B;EAI3D,AAHA,MAAM,8BAA8BC,EAAkB,KAAK,IAAI,EAAE,UAAU,GAC3E,KAAK,OAAO,sBACZ,KAAK,YAAY1B,GACjB,KAAK,oBAAoB0B;CAC1B;AACD,GAGaC,IAAsB,KAGtBC,IAA0B,KAG1BC,IAAoB,KAGpBC,IAAyB,KAGzBC,IAAb,cAAuC,MAAM;CAC5C,YAAY,GAAiB;EAE5B,AADA,MAAMvB,CAAO,GACb,KAAK,OAAO;CACb;AACD,GC50BawB,IAAM;AAOnB,SAAgBC,EAAW,oBAAY,IAAI,KAAK,GAAW;CAC1D,IAAMC,KAAO,MAAc,OAAOC,CAAC,CAAC,CAAC,SAAS,GAAG,GAAG;CACpD,OAAO,GAAGC,EAAI,YAAY,EAAE,GAAGF,EAAIE,EAAI,SAAS,IAAI,CAAC,EAAE,GAAGF,EAAIE,EAAI,QAAQ,CAAC;AAC5E;AAGA,SAASC,EAAM,GAAmC;CACjD,OAAOC,EAAQ,MAAM,MAAM,EAAE,cAAc;AAC5C;AAQA,SAAgBC,EAAiB,GAA0B,GAAwC;CAClG,IAAIF,EAAMC,CAAO,GAChB,OAAOA,EAAQ,MACb,MACA,EAAE,kBACF,EAAE,eAAe,YAAYE,MAC5B,EAAE,eAAe,YAAY,MAAMA,KAAO,EAAE,eAAe,QAC9D;CAED,IAAMC,IAAOH,EAAQ,GAAG,EAAE;CAC1B,OAAOG,KAAQA,EAAK,SAAS,eAAeA,IAAO,KAAA;AACpD;AAOA,SAAgBC,EAAiB,GAA0B,GAAsB;CAOhF,OANIL,EAAMC,CAAO,IACTA,EAAQ,MACb,MACA,EAAE,mBAAmB,EAAE,eAAe,YAAY,MAAM,EAAE,eAAe,WAAWE,EACtF,IAEMD,EAAiBD,GAASE,CAAG,MAAM,KAAA;AAC3C;;;AC9CA,SAAgBG,EAAQ,GAAuC;CAC9D,IAAMC,IAA8B,CAAC;CACrC,KAAK,IAAMC,KAASC,EAAG,QACtB,KAAK,IAAMC,KAAKF,EAAM,UAAU,EAAIE,EAAE,MAAMA,EAAE;CAE/C,OAAOH;AACR;AAGA,SAAgBI,EAAU,GAA2B,GAAoC;CACxF,IAAMC,IAAO,OAAO,KAAKC,CAAC;CAC1B,OAAOD,EAAK,WAAW,OAAO,KAAKF,CAAC,CAAC,CAAC,UAAUE,EAAK,OAAO,MAAMF,EAAEI,OAAOD,EAAEC,EAAE;AAChF"}
package/dist/index.d.ts CHANGED
@@ -79,14 +79,22 @@ export declare interface BlueprintReleaseInfo {
79
79
  name: string;
80
80
  /** ISO 8601: when it was cut. */
81
81
  releaseTime: string;
82
+ /**
83
+ * Why contenthub refuses to pin it, as `CheckBlueprintRelease` answers;
84
+ * empty or absent when Content can pin it. A Release is offered either
85
+ * way, a refused one disabled with its reasons, so a Blueprint author sees
86
+ * why it can't be used rather than where it went.
87
+ */
88
+ refusals?: RefusalReason[];
82
89
  }
83
90
 
84
91
  /**
85
- * The port a host fills with blueprinthub (ADR 0020): the workspace's
86
- * content Blueprints and their Releases, for New Content and the Library's
87
- * Blueprint filter. contenthub-ui depends on no blueprinthub package. A host
88
- * without blueprinthub leaves the port empty: the Library then names
89
- * Blueprints by id, offers no Blueprint filter and cannot create Content.
92
+ * The workspace's content Blueprints and their Releases, for New Content and
93
+ * the Library's Blueprint filter. contenthub serves them itself
94
+ * (`BlueprintCatalogService`, #238): blueprinthub is its direct dependency,
95
+ * not a port a host fills (ADR 0020 as amended), so every screen builds this
96
+ * from its `ContenthubClient` unless a host passes its own, which only tests
97
+ * need.
90
98
  */
91
99
  export declare interface BlueprintSource {
92
100
  /**
@@ -826,6 +834,32 @@ export declare interface ContenthubClient {
826
834
  pageSize?: number;
827
835
  pageToken?: string;
828
836
  }): Promise<ContentList>;
837
+ /**
838
+ * A page of the workspace's content Blueprints Content can be made from:
839
+ * not archived, with at least one Release, whose accessor or name holds
840
+ * `query`. contenthub asks blueprinthub as the caller (#238). Rejects
841
+ * with `ServiceUnavailableError` while blueprinthub gives no answer.
842
+ */
843
+ searchBlueprints(input: {
844
+ query: string;
845
+ pageToken?: string;
846
+ signal?: AbortSignal;
847
+ }): Promise<BlueprintPage>;
848
+ /**
849
+ * Every Release of a Blueprint, newest first, each with contenthub's
850
+ * answer: `refusals` is empty when Content can pin it. Empty for a
851
+ * Blueprint the workspace doesn't have. Rejects with
852
+ * `ServiceUnavailableError` while blueprinthub gives no answer.
853
+ */
854
+ listBlueprintReleases(blueprintId: string): Promise<BlueprintReleaseInfo[]>;
855
+ /**
856
+ * Names the Blueprints of these ids, archived ones and ones without a
857
+ * Release included, so existing Content stays readable after its
858
+ * Blueprint is retired (#241). An unknown id, or one of another
859
+ * workspace, is left out. At most `MAX_BLUEPRINT_IDS`. Rejects with
860
+ * `ServiceUnavailableError` while blueprinthub gives no answer.
861
+ */
862
+ getBlueprints(ids: string[]): Promise<BlueprintInfo[]>;
829
863
  /**
830
864
  * Creates a Content in an open Change Set, pinning a Blueprint Release,
831
865
  * with empty data: its one Chain has one Branch, opened in the Branch
@@ -1874,7 +1908,6 @@ export declare const contenthubTranslations: {
1874
1908
  more: string;
1875
1909
  create: {
1876
1910
  button: string;
1877
- unavailable: string;
1878
1911
  title: string;
1879
1912
  blueprint: string;
1880
1913
  blueprintHelp: string;
@@ -1884,6 +1917,11 @@ export declare const contenthubTranslations: {
1884
1917
  releaseHelp: string;
1885
1918
  releaseRequired: string;
1886
1919
  noRelease: string;
1920
+ noUsableRelease: string;
1921
+ releasesFailed: string;
1922
+ refusedRelease: string;
1923
+ refusedReleases: string;
1924
+ refusedReleaseReasons: string;
1887
1925
  changeSet: string;
1888
1926
  changeSetHelp: string;
1889
1927
  changeSetRequired: string;
@@ -2830,7 +2868,6 @@ export declare const contenthubTranslations: {
2830
2868
  more: string;
2831
2869
  create: {
2832
2870
  button: string;
2833
- unavailable: string;
2834
2871
  title: string;
2835
2872
  blueprint: string;
2836
2873
  blueprintHelp: string;
@@ -2840,6 +2877,11 @@ export declare const contenthubTranslations: {
2840
2877
  releaseHelp: string;
2841
2878
  releaseRequired: string;
2842
2879
  noRelease: string;
2880
+ noUsableRelease: string;
2881
+ releasesFailed: string;
2882
+ refusedRelease: string;
2883
+ refusedReleases: string;
2884
+ refusedReleaseReasons: string;
2843
2885
  changeSet: string;
2844
2886
  changeSetHelp: string;
2845
2887
  changeSetRequired: string;
@@ -3118,9 +3160,10 @@ export declare namespace ContentLibrary {
3118
3160
  export declare interface ContentLibraryProps {
3119
3161
  client: ContenthubClient;
3120
3162
  /**
3121
- * blueprinthub, for Blueprint names, the Blueprint filter and New
3122
- * Content. Without it Blueprints show as ids, there is no Blueprint
3123
- * filter, and New Content is off, saying why (ADR 0020).
3163
+ * Overrides where Blueprint names, the Blueprint filter and New Content
3164
+ * read Blueprints from. Absent, they read contenthub's own
3165
+ * `BlueprintCatalogService` through `client` (#238), which every host
3166
+ * gets; only tests pass one.
3124
3167
  */
3125
3168
  blueprintSource?: BlueprintSource;
3126
3169
  /** Host navigation to a Content's page: a row's click. */
@@ -3160,7 +3203,11 @@ export declare interface ContentPageProps {
3160
3203
  * it; a published Content's page reads Main without it.
3161
3204
  */
3162
3205
  changeSetId?: string;
3163
- /** blueprinthub, for the Blueprint's name in About; without it the Release's own name, or the id. */
3206
+ /**
3207
+ * Overrides where About reads the Blueprint's name. Absent, it reads
3208
+ * contenthub's own `BlueprintCatalogService` through `client` (#238);
3209
+ * a name it can't find falls back to the Release's own name, or the id.
3210
+ */
3164
3211
  blueprintSource?: BlueprintSource;
3165
3212
  /** Host navigation to the Branch editor: after Start editing or Duplicate, or a born Content's Branch. */
3166
3213
  onOpenBranch: (target: OpenBranchTarget) => void;
@@ -3990,7 +4037,6 @@ export declare const i18nResources: {
3990
4037
  more: string;
3991
4038
  create: {
3992
4039
  button: string;
3993
- unavailable: string;
3994
4040
  title: string;
3995
4041
  blueprint: string;
3996
4042
  blueprintHelp: string;
@@ -4000,6 +4046,11 @@ export declare const i18nResources: {
4000
4046
  releaseHelp: string;
4001
4047
  releaseRequired: string;
4002
4048
  noRelease: string;
4049
+ noUsableRelease: string;
4050
+ releasesFailed: string;
4051
+ refusedRelease: string;
4052
+ refusedReleases: string;
4053
+ refusedReleaseReasons: string;
4003
4054
  changeSet: string;
4004
4055
  changeSetHelp: string;
4005
4056
  changeSetRequired: string;
@@ -4946,7 +4997,6 @@ export declare const i18nResources: {
4946
4997
  more: string;
4947
4998
  create: {
4948
4999
  button: string;
4949
- unavailable: string;
4950
5000
  title: string;
4951
5001
  blueprint: string;
4952
5002
  blueprintHelp: string;
@@ -4956,6 +5006,11 @@ export declare const i18nResources: {
4956
5006
  releaseHelp: string;
4957
5007
  releaseRequired: string;
4958
5008
  noRelease: string;
5009
+ noUsableRelease: string;
5010
+ releasesFailed: string;
5011
+ refusedRelease: string;
5012
+ refusedReleases: string;
5013
+ refusedReleaseReasons: string;
4959
5014
  changeSet: string;
4960
5015
  changeSetHelp: string;
4961
5016
  changeSetRequired: string;