@versionone/agility-sdk 1.0.0-alpha.3 → 1.0.0-alpha.5

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/index.d.ts CHANGED
@@ -11,7 +11,8 @@
11
11
  * aborted the caller's signal ended it
12
12
  * commandFailure api/asset answered 200 with failed commands inside (CommandFailureError)
13
13
  * protocol the server answered something the SDK cannot read
14
- * usage a mistake caught before any request (UsageError): fix the call
14
+ * usage a mistake caught before any request (UsageError): nothing was sent, so
15
+ * do not blame the server — fix the call (status is 0 here)
15
16
  * unknown none of the above
16
17
  */
17
18
  type ErrorKind = "auth" | "forbidden" | "notFound" | "invalid" | "transient" | "aborted" | "commandFailure" | "protocol" | "usage" | "unknown";
@@ -74,7 +75,7 @@ interface RequestOptions {
74
75
  /**
75
76
  * Called with a successful response's status and headers before its body
76
77
  * is read — for what the body alone does not say (an attachment's
77
- * Content-Type, say). A transport that cannot see headers may skip it.
78
+ * Content-Type, an ETag). A transport that cannot see headers may skip it.
78
79
  */
79
80
  onResponse?: (response: {
80
81
  status: number;
@@ -82,6 +83,12 @@ interface RequestOptions {
82
83
  get(name: string): string | null;
83
84
  };
84
85
  }) => void;
86
+ /**
87
+ * The request is conditional (an If-None-Match header is set) and a
88
+ * 304 Not Modified is an answer, not a failure: the promise then resolves
89
+ * to undefined after onResponse has seen the 304 and its headers.
90
+ */
91
+ acceptNotModified?: boolean;
85
92
  }
86
93
  interface Transport {
87
94
  request<T>(options: RequestOptions): Promise<T>;
@@ -98,7 +105,9 @@ interface Transport {
98
105
  * failure from an answer, but they are narrow on purpose: only requests the
99
106
  * caller marks idempotent (every GET is; a POST to api/asset is not — a
100
107
  * retried batch write after a timeout is a double write), and only on a
101
- * network error or a 5xx. A 4xx is an answer and is never retried.
108
+ * network error, a 5xx, or a 429 (the instance throttles per token; it
109
+ * sends no Retry-After, but one is honoured when present, up to 30 s). Any
110
+ * other 4xx is an answer and is never retried.
102
111
  */
103
112
  interface FetchTransportConfig {
104
113
  baseUrl: string;
@@ -114,7 +123,12 @@ interface FetchTransportConfig {
114
123
  * timeouts that turn into retries.
115
124
  */
116
125
  timeoutMs?: number;
117
- /** Extra attempts after the first, for idempotent requests only. Default 0. */
126
+ /**
127
+ * Extra attempts after the first, for idempotent requests only (a GET,
128
+ * a query.v1 read, a guarded batch that says so), after a network
129
+ * failure or a 5xx. Default 1: one resend, 150 ms later. 0 turns it off.
130
+ * A plain write is never resent whatever this says.
131
+ */
118
132
  retries?: number;
119
133
  fetchImpl?: typeof fetch;
120
134
  /**
@@ -4286,7 +4300,13 @@ declare function fromWireRow<Row extends Asset = Asset>(row: Record<string, unkn
4286
4300
  interface CommandFailureDetail {
4287
4301
  index: number | null;
4288
4302
  message: string;
4289
- echoed: Record<string, unknown>;
4303
+ /**
4304
+ * The command as the server echoed it, under a generated alias: what a
4305
+ * caller resends after correcting it. Readable on every failure but not
4306
+ * enumerable, so a serialised failure (a receipt, a log line) carries
4307
+ * index, message and violation and not the whole command.
4308
+ */
4309
+ readonly echoed: Record<string, unknown>;
4290
4310
  /** The message read as a validation violation, when it is one. */
4291
4311
  violation: Violation | null;
4292
4312
  }
@@ -4302,7 +4322,7 @@ interface Violation {
4302
4322
  rule: string;
4303
4323
  /** "Story.Scope" when the violation names an attribute; null otherwise. */
4304
4324
  attribute: AttributeTokenRef | null;
4305
- /** The loc-2 tag naming what was violated, when the message carries one. */
4325
+ /** The loc-2 tag naming what was violated (`AttributeDefinition'Scope'Story`), when the message carries one; null for the token spelling. */
4306
4326
  tag: string | null;
4307
4327
  }
4308
4328
  /** The violation a failure message describes, or null when it is not one. */
@@ -4311,6 +4331,8 @@ declare function parseViolation(message: string): Violation | null;
4311
4331
  declare function failuresOf<Row extends Asset = Asset>(response: AssetApiResponse<Row>): CommandFailureDetail[];
4312
4332
  /** What a batch did, in the model's terms: the services read this, never the envelope. */
4313
4333
  interface Outcome<Row extends Asset = Asset> {
4334
+ /** The server's id for the request: what to quote when asking about a batch. Null for an outcome merged from several sends. */
4335
+ requestId: string | null;
4314
4336
  created: Oid[];
4315
4337
  modified: Oid[];
4316
4338
  operated: Oid[];
@@ -4319,7 +4341,12 @@ interface Outcome<Row extends Asset = Asset> {
4319
4341
  queryResults: (Row[] | null)[];
4320
4342
  durationSeconds: number | null;
4321
4343
  }
4322
- /** The outcome of a (translated) response: OIDs momentless, failures normalised. */
4344
+ /**
4345
+ * The outcome of a (translated) response: OIDs momentless, failures
4346
+ * normalised. Every field has a default, so a partial envelope (a test fake
4347
+ * that sends only queryResult) still yields a complete Outcome; consumers'
4348
+ * fakes rely on that, and the unit tests keep it so.
4349
+ */
4323
4350
  declare function outcomeOf<Row extends Asset = Asset>(response: AssetApiResponse<Row>): Outcome<Row>;
4324
4351
  /** An outcome with nothing in it, to merge several sends into. */
4325
4352
  declare const emptyOutcome: <Row extends Asset = Asset>() => Outcome<Row>;
@@ -4536,6 +4563,10 @@ declare class TypeCache {
4536
4563
  /** Loaded types; null records that the instance has no such type, so it is not asked for again. */
4537
4564
  readonly types: Map<string, AssetType | null>;
4538
4565
  readonly loading: Map<string, Promise<AssetType | null>>;
4566
+ /** The schema's tag the loaded types came with (meta.v1's ETag, one for the whole schema); null until a load, or for a seeded cache. */
4567
+ etag: string | null;
4568
+ /** Forget every loaded type (and the tag): the next query loads afresh. In-flight loads finish into the cache as before. */
4569
+ clear(): void;
4539
4570
  /** A cache seeded from a metamodel document. */
4540
4571
  static fromMetamodel(metamodel: Metamodel): TypeCache;
4541
4572
  }
@@ -4568,6 +4599,18 @@ declare class Schema implements AttributeLookup {
4568
4599
  * any other failure (auth, network) is thrown, not swallowed.
4569
4600
  */
4570
4601
  load(token: AssetTypeToken): Promise<AssetType | null>;
4602
+ /**
4603
+ * Has the instance's schema changed since these types were loaded? One
4604
+ * small conditional read of meta.v1. Unchanged: nothing happens.
4605
+ * Changed (or never tagged, or the transport cannot see headers): the
4606
+ * loaded types are dropped, so the next query loads them again, and the
4607
+ * new tag is kept. Answers whether it changed and the current tag. A
4608
+ * schema without a transport (seeded) never changes.
4609
+ */
4610
+ revalidate(): Promise<{
4611
+ changed: boolean;
4612
+ etag: string | null;
4613
+ }>;
4571
4614
  /**
4572
4615
  * Load whatever the queries in a batch need to have their rows translated:
4573
4616
  * the `from` types, then the types behind every relation hop and sub-select,
@@ -4773,6 +4816,40 @@ declare function reversible(transport: Transport, receipt: Pick<Receipt, "revers
4773
4816
  reactivated: Oid[];
4774
4817
  }>;
4775
4818
 
4819
+ /**
4820
+ * The fields service: what a form for an asset type in a scope needs to
4821
+ * know, from three sources the API keeps apart —
4822
+ * - meta.v1 (through the schema): which attributes are REQUIRED to
4823
+ * create one (IsRequired and writable: Name and Scope on a Story);
4824
+ * - api/visibleFields: which attributes the product SHOWS for the type
4825
+ * in that scope, custom fields included once configured;
4826
+ * - the scope's Scheme: its IMPORTANT fields (Scheme.ImportantFields, a
4827
+ * list of attribute tokens) and whether they are enforced at close
4828
+ * (Scheme.IsRequiredAtClose).
4829
+ * One call, one answer, every list spelled as bare attribute names.
4830
+ */
4831
+
4832
+ interface FieldsOf {
4833
+ type: AssetTypeToken;
4834
+ scope: Oid;
4835
+ /** The scope's Scheme; null when the scope has none. */
4836
+ scheme: Oid | null;
4837
+ /** Attributes the server requires on a create (meta: IsRequired, writable). */
4838
+ required: string[];
4839
+ /** Attributes the product shows for the type in this scope (api/visibleFields). */
4840
+ visible: string[];
4841
+ /** The scheme's important fields that belong to this type (or an ancestor); [] when the scheme names none. */
4842
+ important: string[];
4843
+ /** Whether the scheme enforces its important fields when an asset is closed. */
4844
+ requiredAtClose: boolean;
4845
+ }
4846
+ /**
4847
+ * An important-field token as the scheme spells it ("Story.Owners", or a
4848
+ * bare "Owners") reduced to the attribute name when it belongs to one of
4849
+ * the types given; null otherwise.
4850
+ */
4851
+ declare function importantName(token: string, types: readonly AssetTypeToken[]): string | null;
4852
+
4776
4853
  /**
4777
4854
  * The guard: an api/asset batch sent as a compare-and-set, so a change only
4778
4855
  * lands on an asset nobody else has changed since it was read. Ported from
@@ -4938,6 +5015,108 @@ declare namespace loc2 {
4938
5015
  export type { loc2_Localizations as Localizations, loc2_LocalizeOptions as LocalizeOptions };
4939
5016
  }
4940
5017
 
5018
+ interface TokenRef {
5019
+ href: string;
5020
+ tokenref: AttributeTokenRef;
5021
+ }
5022
+ interface NameRef {
5023
+ href: string;
5024
+ nameref: AssetTypeToken;
5025
+ }
5026
+ interface AttributeDefinitionDocument {
5027
+ HREF?: string;
5028
+ _type: "AttributeDefinition";
5029
+ Name: string;
5030
+ Token: AttributeTokenRef;
5031
+ DisplayName: string;
5032
+ AttributeType: AttributeType;
5033
+ IsReadOnly: boolean;
5034
+ IsRequired: boolean;
5035
+ IsMultivalue: boolean;
5036
+ IsCanned: boolean;
5037
+ IsCustom: boolean;
5038
+ /** Present on an inherited attribute: the defining ancestor's attribute. */
5039
+ Base?: TokenRef;
5040
+ ReciprocalRelation?: TokenRef;
5041
+ OrderByAttribute?: TokenRef;
5042
+ DisplayByAttribute?: TokenRef;
5043
+ /** Present on a Relation. */
5044
+ RelatedAsset?: NameRef;
5045
+ }
5046
+ interface AssetTypeDocument {
5047
+ HREF?: string;
5048
+ Version?: string;
5049
+ _type: "AssetType";
5050
+ Token: AssetTypeToken;
5051
+ /** The delivered Name is a reference to the type's Name attribute; the token is the name. */
5052
+ Name: TokenRef | string;
5053
+ DisplayName: string;
5054
+ Abstract: boolean;
5055
+ /** Absent on a root type. */
5056
+ Base?: NameRef;
5057
+ DefaultOrderBy?: TokenRef;
5058
+ DefaultDisplayBy?: TokenRef;
5059
+ ShortName?: TokenRef;
5060
+ Description?: TokenRef;
5061
+ Attributes: Record<string, AttributeDefinitionDocument>;
5062
+ Operations?: Record<string, unknown>;
5063
+ Rules?: Record<string, unknown>;
5064
+ }
5065
+ interface MetamodelDocument {
5066
+ HREF?: string;
5067
+ Version: string;
5068
+ AssetTypes: Record<string, AssetTypeDocument>;
5069
+ }
5070
+ declare function toAttributeDefinition(doc: AttributeDefinitionDocument): AttributeDefinition;
5071
+ declare function toAssetType(doc: AssetTypeDocument): AssetType;
5072
+ declare function toMetamodel(doc: MetamodelDocument): Metamodel;
5073
+ /** Is this a metamodel document as meta.v1 delivers it? (A downloaded metamodel.json, say.) */
5074
+ declare function isMetamodelDocument(value: unknown): value is MetamodelDocument;
5075
+ /** A conditional read: the tag a previous answer carried. With it, an unchanged resource is null. */
5076
+ interface ConditionalOptions {
5077
+ ifNoneMatch?: string | null;
5078
+ }
5079
+ /** What a read answered, with the schema's tag as the server sent it (null when it sent none). */
5080
+ interface Tagged<T> {
5081
+ value: T;
5082
+ etag: string | null;
5083
+ }
5084
+ declare function getMetamodel(transport: Transport): Promise<Metamodel>;
5085
+ /** The metamodel with its tag; null when `ifNoneMatch` still matches (nothing was downloaded). */
5086
+ declare function readMetamodel(transport: Transport, options?: ConditionalOptions): Promise<Tagged<Metamodel> | null>;
5087
+ declare function getAssetType(transport: Transport, token: AssetTypeToken): Promise<AssetType>;
5088
+ /** One type with the schema's tag; null when `ifNoneMatch` still matches. */
5089
+ declare function readAssetType(transport: Transport, token: AssetTypeToken, options?: ConditionalOptions): Promise<Tagged<AssetType> | null>;
5090
+ /**
5091
+ * The schema's current tag, from one small read, or null when the server
5092
+ * sends none. With `ifNoneMatch`, "unchanged" is answered as that same tag
5093
+ * without a body — the cheapest way to ask whether anything in meta moved.
5094
+ */
5095
+ declare function etag(transport: Transport, options?: ConditionalOptions): Promise<string | null>;
5096
+ declare function getAttributeDefinition(transport: Transport, tokenref: AttributeTokenRef): Promise<AttributeDefinition>;
5097
+
5098
+ type meta_AssetTypeDocument = AssetTypeDocument;
5099
+ type meta_AttributeDefinitionDocument = AttributeDefinitionDocument;
5100
+ type meta_ConditionalOptions = ConditionalOptions;
5101
+ type meta_MetamodelDocument = MetamodelDocument;
5102
+ type meta_NameRef = NameRef;
5103
+ type meta_Tagged<T> = Tagged<T>;
5104
+ type meta_TokenRef = TokenRef;
5105
+ declare const meta_etag: typeof etag;
5106
+ declare const meta_getAssetType: typeof getAssetType;
5107
+ declare const meta_getAttributeDefinition: typeof getAttributeDefinition;
5108
+ declare const meta_getMetamodel: typeof getMetamodel;
5109
+ declare const meta_isMetamodelDocument: typeof isMetamodelDocument;
5110
+ declare const meta_readAssetType: typeof readAssetType;
5111
+ declare const meta_readMetamodel: typeof readMetamodel;
5112
+ declare const meta_toAssetType: typeof toAssetType;
5113
+ declare const meta_toAttributeDefinition: typeof toAttributeDefinition;
5114
+ declare const meta_toMetamodel: typeof toMetamodel;
5115
+ declare namespace meta {
5116
+ export { meta_etag as etag, meta_getAssetType as getAssetType, meta_getAttributeDefinition as getAttributeDefinition, meta_getMetamodel as getMetamodel, meta_isMetamodelDocument as isMetamodelDocument, meta_readAssetType as readAssetType, meta_readMetamodel as readMetamodel, meta_toAssetType as toAssetType, meta_toAttributeDefinition as toAttributeDefinition, meta_toMetamodel as toMetamodel };
5117
+ export type { meta_AssetTypeDocument as AssetTypeDocument, meta_AttributeDefinitionDocument as AttributeDefinitionDocument, meta_ConditionalOptions as ConditionalOptions, meta_MetamodelDocument as MetamodelDocument, meta_NameRef as NameRef, meta_Tagged as Tagged, meta_TokenRef as TokenRef };
5118
+ }
5119
+
4941
5120
  interface AssetRefDocument {
4942
5121
  _type: "Asset";
4943
5122
  href: string;
@@ -5012,6 +5191,33 @@ interface ReadResult<Row extends Asset = Asset> {
5012
5191
  declare const list: <Row extends Asset = Asset>(transport: Transport, type: string, params: ReadParams) => Promise<ReadResult<Row>>;
5013
5192
  /** One asset by OID. */
5014
5193
  declare function get<Row extends Asset = Asset>(transport: Transport, oid: Oid, select?: string[]): Promise<Row>;
5194
+ /**
5195
+ * What an operation answered with: the asset the server returned, as an
5196
+ * OID token — for Copy the copy, for anything else the operated asset —
5197
+ * and the moment the server stamped on it.
5198
+ */
5199
+ interface OperationResult {
5200
+ oid: Oid;
5201
+ moment: string | null;
5202
+ }
5203
+ /**
5204
+ * Run an operation (Copy, Inactivate, …) through rest-1, for its result.
5205
+ * api/asset's `execute` performs the same operations but reports only the
5206
+ * operated asset, so a Copy's new OID is unobservable there; rest-1 answers
5207
+ * it. Not idempotent: never retried.
5208
+ */
5209
+ declare function operate(transport: Transport, oid: Oid, op: string): Promise<OperationResult>;
5210
+ /** A new asset's template as the model carries it: the attributes the initializer set, no `_oid`. */
5211
+ type Template<Row extends Asset = Asset> = Partial<Omit<Row, "_oid">>;
5212
+ /**
5213
+ * The template for a new asset of `type` in a context (a Scope, a parent
5214
+ * asset): what the server's initializer would fill in — defaults nothing
5215
+ * else exposes. Idempotent, like any GET. Without a context the template
5216
+ * is empty, and an unknown context is echoed back, not refused.
5217
+ */
5218
+ declare function template<Row extends Asset = Asset>(transport: Transport, type: string, options?: {
5219
+ ctx?: Oid;
5220
+ }): Promise<Template<Row>>;
5015
5221
  /** A bounded history read: one row per moment, _oid carrying the moment. */
5016
5222
  declare const history: <Row extends Asset = Asset>(transport: Transport, target: string, params: ReadParams) => Promise<ReadResult<Row>>;
5017
5223
 
@@ -5019,18 +5225,22 @@ type rest1_AssetDocument = AssetDocument;
5019
5225
  type rest1_AssetRefDocument = AssetRefDocument;
5020
5226
  type rest1_AssetsDocument = AssetsDocument;
5021
5227
  type rest1_AttributeDocument = AttributeDocument;
5228
+ type rest1_OperationResult = OperationResult;
5022
5229
  type rest1_ReadParams = ReadParams;
5023
5230
  type rest1_ReadResult<Row extends Asset = Asset> = ReadResult<Row>;
5024
5231
  type rest1_RelationDocument = RelationDocument;
5232
+ type rest1_Template<Row extends Asset = Asset> = Template<Row>;
5025
5233
  declare const rest1_fromAssetDocument: typeof fromAssetDocument;
5026
5234
  declare const rest1_get: typeof get;
5027
5235
  declare const rest1_history: typeof history;
5028
5236
  declare const rest1_list: typeof list;
5029
5237
  declare const rest1_momentless: typeof momentless;
5238
+ declare const rest1_operate: typeof operate;
5239
+ declare const rest1_template: typeof template;
5030
5240
  declare const rest1_toQuery: typeof toQuery;
5031
5241
  declare namespace rest1 {
5032
- export { rest1_fromAssetDocument as fromAssetDocument, rest1_get as get, rest1_history as history, rest1_list as list, rest1_momentless as momentless, rest1_toQuery as toQuery };
5033
- export type { rest1_AssetDocument as AssetDocument, rest1_AssetRefDocument as AssetRefDocument, rest1_AssetsDocument as AssetsDocument, rest1_AttributeDocument as AttributeDocument, rest1_ReadParams as ReadParams, rest1_ReadResult as ReadResult, rest1_RelationDocument as RelationDocument };
5242
+ export { rest1_fromAssetDocument as fromAssetDocument, rest1_get as get, rest1_history as history, rest1_list as list, rest1_momentless as momentless, rest1_operate as operate, rest1_template as template, rest1_toQuery as toQuery };
5243
+ export type { rest1_AssetDocument as AssetDocument, rest1_AssetRefDocument as AssetRefDocument, rest1_AssetsDocument as AssetsDocument, rest1_AttributeDocument as AttributeDocument, rest1_OperationResult as OperationResult, rest1_ReadParams as ReadParams, rest1_ReadResult as ReadResult, rest1_RelationDocument as RelationDocument, rest1_Template as Template };
5034
5244
  }
5035
5245
 
5036
5246
  interface ClientOptions {
@@ -5076,12 +5286,15 @@ type Me = Pick<Member, "_oid" | "Name" | "Username" | "Nickname" | "Email">;
5076
5286
  * every write answers in the model's terms (an Outcome, never an envelope).
5077
5287
  *
5078
5288
  * Reads: `query`, `queries`, `get`, `queryPage`, `pages`, `all`, `me`. A
5079
- * query body is the same everywhere; the client picks the endpoint
5080
- * (query.v1 for plain reads — read-only by construction, so a request can
5081
- * be retried like a GET; api/asset where a total is wanted; rest-1 behind
5082
- * `data` for deleted assets and history). Writes: `assets.send`,
5083
- * `assets.sendGuarded`, `batch.run`. Services: `resolve`, `attachments`,
5084
- * `embeddedImages`, `schema`, `localize`, `urls`.
5289
+ * query body is the same everywhere; the client picks the endpoint.
5290
+ * query.v1 answers rows alone — the lightest response, and read-only by
5291
+ * construction, so a request can be resent like a GET — but its shape has
5292
+ * nowhere to put a total; api/asset reports one (`needTotal`) beside the
5293
+ * rows, which is why `queryPage` goes there and `query` does not. rest-1
5294
+ * sits behind `data` for what neither does: deleted assets, history, a
5295
+ * new asset's template, an operation's result. Writes: `assets.send`,
5296
+ * `assets.sendGuarded`, `batch.run`, `copy`. Services: `resolve`,
5297
+ * `fields`, `attachments`, `embeddedImages`, `schema`, `localize`, `urls`.
5085
5298
  */
5086
5299
  declare class AgilityApiClient {
5087
5300
  readonly transport: Transport;
@@ -5097,9 +5310,12 @@ declare class AgilityApiClient {
5097
5310
  withSignal(signal: AbortSignal): AgilityApiClient;
5098
5311
  /**
5099
5312
  * One query, its rows, translated. Sent to query.v1: it cannot write, so
5100
- * the request is retried like a GET after a network failure or a 5xx. A
5101
- * page is required; a query the server refuses throws (kind "invalid"),
5102
- * never an empty result.
5313
+ * the request is marked idempotent and the transport may resend it after
5314
+ * a network failure or a 5xx — when `retries` is set above its default
5315
+ * of 0. A page is required; a query the server refuses throws an
5316
+ * ApiError (kind "invalid", code QUERY_REJECTED; `message` holds the
5317
+ * server's sentences, `details` its whole error document), never an
5318
+ * empty result.
5103
5319
  */
5104
5320
  query<const F extends From, const Q extends QueryBody<F>>(q: Q & QueryBody<F>): Promise<RowOf<Q>[]>;
5105
5321
  query<Row extends Asset = Asset>(q: QueryBody): Promise<Row[]>;
@@ -5134,11 +5350,21 @@ declare class AgilityApiClient {
5134
5350
  all<Row extends Asset = Asset>(q: QueryBody, options?: PagesOptions): Promise<Row[]>;
5135
5351
  /** The member these credentials belong to (Member.IsSelf, live 2026-11-12): what a comment's Author is. */
5136
5352
  me(): Promise<Me>;
5137
- /** meta.v1: the instance's schema, raw. (The translated, cached view is `schema`.) */
5353
+ /**
5354
+ * meta.v1: the instance's schema, raw. (The translated, cached view is
5355
+ * `schema`; `schema.revalidate()` drops it when the schema's tag moves.)
5356
+ * `read` and `readType` are conditional: pass the tag a previous answer
5357
+ * carried and an unchanged schema answers null without a download —
5358
+ * meta.v1 sends one strong ETag for the whole schema. `etag()` reads that
5359
+ * tag alone, from the smallest resource.
5360
+ */
5138
5361
  readonly meta: {
5139
5362
  metamodel: () => Promise<Metamodel>;
5363
+ read: (options?: ConditionalOptions) => Promise<Tagged<Metamodel> | null>;
5140
5364
  assetType: (token: string) => Promise<AssetType>;
5365
+ readType: (token: string, options?: ConditionalOptions) => Promise<Tagged<AssetType> | null>;
5141
5366
  attributeDefinition: (tokenref: `${string}.${string}`) => Promise<AttributeDefinition>;
5367
+ etag: (options?: ConditionalOptions) => Promise<string | null>;
5142
5368
  };
5143
5369
  /**
5144
5370
  * loc-2.v1: labels for tags, in one request (meta's DisplayName values are
@@ -5147,16 +5373,39 @@ declare class AgilityApiClient {
5147
5373
  */
5148
5374
  localize(tags: readonly string[], options?: LocalizeOptions): Promise<Localizations>;
5149
5375
  /**
5150
- * rest-1.v1, for what query.v1 cannot do: deleted assets (`deleted:
5151
- * true`), one asset by OID without a page, and history (one row per
5152
- * moment). Parameters are spelled as a query's (`select`, `filter`).
5376
+ * rest-1.v1, for what the other endpoints cannot do: deleted assets
5377
+ * (`deleted: true`), one asset by OID without a page, history (one row
5378
+ * per moment), a new asset's template (`template`: what the type's
5379
+ * initializer fills in for a context — a Timebox's next name and dates,
5380
+ * a Story's carry-over from a Request), and an operation's result
5381
+ * (`operate`: api/asset performs a Copy but never says what it made;
5382
+ * rest-1 answers the new OID). Parameters are spelled as a query's
5383
+ * (`select`, `filter`).
5153
5384
  */
5154
5385
  readonly data: {
5155
5386
  list: <Row extends Asset = Asset>(type: string, params: ReadParams) => Promise<ReadResult<Row>>;
5156
5387
  get: <Row extends Asset = Asset>(oid: string, select?: string[]) => Promise<Row>;
5157
5388
  history: <Row extends Asset = Asset>(target: string, params: ReadParams) => Promise<ReadResult<Row>>;
5389
+ template: <F extends From>(type: F, options?: {
5390
+ ctx?: Oid;
5391
+ }) => Promise<Partial<Omit<TypeOf<F>, "_oid">>>;
5392
+ operate: (oid: Oid, op: string) => Promise<OperationResult>;
5158
5393
  };
5159
- /** @deprecated since 1.0.0-alpha.3: `client.query` / `client.queries` read through query.v1. Removed in 1.0.0. */
5394
+ /** Copy an asset (the server's Copy operation) and answer the copy's OID: the one thing api/asset's `execute: "Copy"` does not say. */
5395
+ copy(oid: Oid): Promise<Oid>;
5396
+ /**
5397
+ * What a form needs for an asset type in a scope: the attributes the
5398
+ * server requires to create one (meta), the ones the product shows there
5399
+ * (api/visibleFields, custom fields included once configured), and the
5400
+ * scope's scheme's important fields and whether they are enforced at
5401
+ * close. `visible` alone answers for several types and scopes at once.
5402
+ */
5403
+ readonly fields: {
5404
+ describe: (type: From, scope: Oid) => Promise<FieldsOf>;
5405
+ visible: (types: readonly From[], scopes: readonly Oid[]) => Promise<Record<string, string[]>>;
5406
+ visibleByAsset: (oid: Oid) => Promise<string[]>;
5407
+ };
5408
+ /** @deprecated since 1.0.0-alpha.3: use `client.query` / `client.queries` (the same endpoint, query.v1; only the name moved). Removed in 1.0.0. */
5160
5409
  readonly queryV1: {
5161
5410
  query: <Row extends Asset = Asset>(q: QueryBody) => Promise<Row[]>;
5162
5411
  queries: <Row extends Asset = Asset>(qs: QueryBody[]) => Promise<Row[][]>;
@@ -5181,7 +5430,7 @@ declare class AgilityApiClient {
5181
5430
  * cover.
5182
5431
  */
5183
5432
  sendGuarded: <Row extends Asset = Asset>(commands: Command[], options?: Pick<SendOptions, "throwOnFailure">) => Promise<GuardedResult<Row>>;
5184
- /** @deprecated since 1.0.0-alpha.3: use `client.query` (or `client.queryPage` for a total). Removed in 1.0.0. */
5433
+ /** @deprecated since 1.0.0-alpha.3: use `client.query` (rows, through query.v1) or `client.queryPage` (rows and a total, through api/asset as this does). Removed in 1.0.0. */
5185
5434
  query: <Row extends Asset = Asset>(q: QueryBody) => Promise<Row[]>;
5186
5435
  /** @deprecated since 1.0.0-alpha.3: use `client.queries`. Removed in 1.0.0. */
5187
5436
  queries: <Row extends Asset = Asset>(qs: QueryBody[]) => Promise<Row[][]>;
@@ -5265,91 +5514,23 @@ declare class AgilityApiClient {
5265
5514
  };
5266
5515
  /** Where a browser opens things on this instance: an asset's page, an attachment's bytes, an embedded image. */
5267
5516
  readonly urls: {
5268
- /** The asset's page: assetdetail.v1 redirects to the type's own detail page (live 2026-11-12). */
5269
- asset: (oid: Oid) => string;
5517
+ /**
5518
+ * The asset's page, from an OID token or an asset Number (S-01001,
5519
+ * what a person typed and what a message shows): assetdetail.v1
5520
+ * resolves either and redirects to the type's own detail page; a signed-
5521
+ * out reader lands there after logging in. Anything else is a UsageError.
5522
+ */
5523
+ asset: (ref: Oid | string) => string;
5270
5524
  attachment: (id: string | number) => string;
5271
5525
  embeddedImage: (id: string | number) => string;
5272
5526
  };
5273
5527
  }
5274
5528
 
5275
- interface TokenRef {
5276
- href: string;
5277
- tokenref: AttributeTokenRef;
5278
- }
5279
- interface NameRef {
5280
- href: string;
5281
- nameref: AssetTypeToken;
5282
- }
5283
- interface AttributeDefinitionDocument {
5284
- HREF?: string;
5285
- _type: "AttributeDefinition";
5286
- Name: string;
5287
- Token: AttributeTokenRef;
5288
- DisplayName: string;
5289
- AttributeType: AttributeType;
5290
- IsReadOnly: boolean;
5291
- IsRequired: boolean;
5292
- IsMultivalue: boolean;
5293
- IsCanned: boolean;
5294
- IsCustom: boolean;
5295
- /** Present on an inherited attribute: the defining ancestor's attribute. */
5296
- Base?: TokenRef;
5297
- ReciprocalRelation?: TokenRef;
5298
- OrderByAttribute?: TokenRef;
5299
- DisplayByAttribute?: TokenRef;
5300
- /** Present on a Relation. */
5301
- RelatedAsset?: NameRef;
5302
- }
5303
- interface AssetTypeDocument {
5304
- HREF?: string;
5305
- Version?: string;
5306
- _type: "AssetType";
5307
- Token: AssetTypeToken;
5308
- /** The delivered Name is a reference to the type's Name attribute; the token is the name. */
5309
- Name: TokenRef | string;
5310
- DisplayName: string;
5311
- Abstract: boolean;
5312
- /** Absent on a root type. */
5313
- Base?: NameRef;
5314
- DefaultOrderBy?: TokenRef;
5315
- DefaultDisplayBy?: TokenRef;
5316
- ShortName?: TokenRef;
5317
- Description?: TokenRef;
5318
- Attributes: Record<string, AttributeDefinitionDocument>;
5319
- Operations?: Record<string, unknown>;
5320
- Rules?: Record<string, unknown>;
5321
- }
5322
- interface MetamodelDocument {
5323
- HREF?: string;
5324
- Version: string;
5325
- AssetTypes: Record<string, AssetTypeDocument>;
5326
- }
5327
- declare function toAttributeDefinition(doc: AttributeDefinitionDocument): AttributeDefinition;
5328
- declare function toAssetType(doc: AssetTypeDocument): AssetType;
5329
- declare function toMetamodel(doc: MetamodelDocument): Metamodel;
5330
- /** Is this a metamodel document as meta.v1 delivers it? (A downloaded metamodel.json, say.) */
5331
- declare function isMetamodelDocument(value: unknown): value is MetamodelDocument;
5332
- declare function getMetamodel(transport: Transport): Promise<Metamodel>;
5333
- declare function getAssetType(transport: Transport, token: AssetTypeToken): Promise<AssetType>;
5334
- declare function getAttributeDefinition(transport: Transport, tokenref: AttributeTokenRef): Promise<AttributeDefinition>;
5335
-
5336
- type meta_AssetTypeDocument = AssetTypeDocument;
5337
- type meta_AttributeDefinitionDocument = AttributeDefinitionDocument;
5338
- type meta_MetamodelDocument = MetamodelDocument;
5339
- type meta_NameRef = NameRef;
5340
- type meta_TokenRef = TokenRef;
5341
- declare const meta_getAssetType: typeof getAssetType;
5342
- declare const meta_getAttributeDefinition: typeof getAttributeDefinition;
5343
- declare const meta_getMetamodel: typeof getMetamodel;
5344
- declare const meta_isMetamodelDocument: typeof isMetamodelDocument;
5345
- declare const meta_toAssetType: typeof toAssetType;
5346
- declare const meta_toAttributeDefinition: typeof toAttributeDefinition;
5347
- declare const meta_toMetamodel: typeof toMetamodel;
5348
- declare namespace meta {
5349
- export { meta_getAssetType as getAssetType, meta_getAttributeDefinition as getAttributeDefinition, meta_getMetamodel as getMetamodel, meta_isMetamodelDocument as isMetamodelDocument, meta_toAssetType as toAssetType, meta_toAttributeDefinition as toAttributeDefinition, meta_toMetamodel as toMetamodel };
5350
- export type { meta_AssetTypeDocument as AssetTypeDocument, meta_AttributeDefinitionDocument as AttributeDefinitionDocument, meta_MetamodelDocument as MetamodelDocument, meta_NameRef as NameRef, meta_TokenRef as TokenRef };
5529
+ /** What query.v1 said about each refused query: its exception type and message. */
5530
+ interface QueryRejection {
5531
+ type: string | null;
5532
+ message: string;
5351
5533
  }
5352
-
5353
5534
  /**
5354
5535
  * Several queries in one request; one array of rows per query, in order, []
5355
5536
  * where a query matched nothing. A page is required on every query. A
@@ -5360,14 +5541,27 @@ declare function queries<Row extends Asset = Asset>(transport: Transport, qs: Qu
5360
5541
  /** One query, its rows. */
5361
5542
  declare function query<Row extends Asset = Asset>(transport: Transport, q: QueryBody, options?: ReadOptions): Promise<Row[]>;
5362
5543
 
5544
+ type queryV1_QueryRejection = QueryRejection;
5363
5545
  declare const queryV1_queries: typeof queries;
5364
5546
  declare const queryV1_query: typeof query;
5365
5547
  declare namespace queryV1 {
5548
+ export { queryV1_queries as queries, queryV1_query as query };
5549
+ export type { queryV1_QueryRejection as QueryRejection };
5550
+ }
5551
+
5552
+ /** The attributes shown for each type in the scopes given: a map from type token to sorted attribute names. */
5553
+ declare function visibleFields(transport: Transport, types: readonly AssetTypeToken[], scopes: readonly Oid[]): Promise<Record<AssetTypeToken, string[]>>;
5554
+ /** The attributes shown for one asset, in its own Scope. */
5555
+ declare function visibleFieldsByAsset(transport: Transport, oid: Oid): Promise<string[]>;
5556
+
5557
+ declare const fields_visibleFields: typeof visibleFields;
5558
+ declare const fields_visibleFieldsByAsset: typeof visibleFieldsByAsset;
5559
+ declare namespace fields {
5366
5560
  export {
5367
- queryV1_queries as queries,
5368
- queryV1_query as query,
5561
+ fields_visibleFields as visibleFields,
5562
+ fields_visibleFieldsByAsset as visibleFieldsByAsset,
5369
5563
  };
5370
5564
  }
5371
5565
 
5372
- export { ASSET_STATE_CODES, AgilityApiClient, ApiError, AttachmentUploadError, BatchRecordError, BatchSendError, CommandFailureError, INLINE_LIMIT, INVERSE, NUMBER_ROOTS, CHUNK as RESOLVE_CHUNK, Schema, TypeCache, UNGUARDABLE_TYPES, UnguardableError, UsageError, WrappedError, assetApi, assetStateOf, attachment, createFetchTransport, describe as describeBatch, guard, isAssetNumber, isOidToken, kindOf, loc2, meta, momentless, namesOf, parseOid, parseViolation, queryV1, resolveNumbers, resolveRef, rest1, reverseOf, reversible, runBatch, select, sendGuarded, snapshot, stampsOf, toOid, touchedBy, typeOfOid, unguardable };
5373
- export type { Access, Actual, Allocation, Application, Asset, AssetApiResponse, AssetChangedEventDefinition, AssetCreatedEventDefinition, AssetDocument, AssetNumberAttributeDefinition, AssetStateValue, AssetType, AssetTypeMap, AssetTypeName, AssetTypeToken, AssetsDocument, Attachment, AddOptions as AttachmentAddOptions, AttachmentCategory, AttachmentInfo, AttributeAddedEventDefinition, AttributeChangedEventDefinition, AttributeDefinition, AttributeLookup, AttributeRemovedEventDefinition, AttributeTokenRef, AttributeType, AttributeValue, BaseAsset, BatchOptions, Budget, BuildProject, BuildRun, BuildSource, BuildStatus, Bundle, BusinessRule, Bytes, CalendarEvent, CalendarEventCategory, Capacity, ChangeSet, ClassOfService, ClientConfig, ClientOptions, Command, CommandBody, CommandFailureDetail, CommandValue, Community, Concept, ConcreteAssetTypeName, Conversation, CreateBody, CreateType, CredentialsAttributeDefinition, CustomAttributes, CustomList, DateString, DefaultRule, Defect, DefectResolution, DefectType, Delivery, DeliveryCategory, Described, EmbeddedImage$1 as EmbeddedImage, Environment, Epic, EpicCategory, EpicPriority, EpicStatus, ErrorKind, ExecuteBody, ExecuteSecurityCheckAttributeDefinition, Expression, ExpressionImage, ExpressionSpace, ExternalAction, ExternalActionInvocation, FetchTransportConfig, From, Goal, GoalCategory, GoalPriority, Grant, GuardedResult, HierarchyRelationDefinition, Idea, IdeaCategory, IdeaChangeSet, IdeaComment, IdeaForum, IdeaStatus, IdeaUser, IdeasUserCache, Image, Issue, IssueCategory, IssuePriority, IssueResolution, IssueStatus, KeyResult, KeyResultCommitment, KeyResultUnit, Label, Link, LinkCategory, List, Localizations, LocalizeOptions, ManyToManyRelationDefinition, Me, Member, MemberLabel, Message, MessageReceipt, Metamodel, Milestone, MilestoneCategory, MultivalueAttributeDefinition, NameLookupFailure, Named, NoteCategory, Oid, OidParts, Okr, OkrObjective, OkrSession, OneToManyRelationDefinition, OperationExecutedEventDefinition, Outcome, Page, PagesOptions, PasswordAttributeDefinition, Phase, PlanningLevel, PlanningRoom, PrimaryWorkitem, PrincipalAttributeDefinition, Publication, QueryBody, ReadOptions, ReadParams, ReadResult, Receipt, Ref, RegressionPlan, RegressionSuite, RegressionTest, RegressionTestStatus, Release, Request, RequestBody, RequestCategory, RequestOptions, RequestPriority, RequestResolution, RequestStatus, Resolution, ResolvedAsset, ResponseType, Retrospective, RetrospectivePrompt, RetrospectiveTopic, Reverse, Roadmap, Role, Room, RowContext, RowOf, RowsOf, SavedView, Schedule, Scheme, Scope, ScopeLabel, ScopeStatus, SelectKey, SelectPath, SelectValue, Selected, SendOptions, SimpleAttributeDefinition, State, Status, Story, StoryCategory, StorySource, StoryStatus, StrategicTheme, StrategicThemeLevel, Subscription, SubscriptionTerm, SyntheticAttributeDefinition, Task, TaskCategory, TaskSource, TaskStatus, Team, TeamRoom, TeamWorkflow, Test, TestCategory, TestRun, TestSet, TestStatus, TestSuite, Theme, ThemeCategory, ThemeLabel, ThemeSource, ThemeStatus, Timebox, Timesheet, Topic, Transport, TriggerType, TypeOf, UnauthorizedContext, UnauthorizedDecision, Unguardable, UpdateBody, UpdateSecurityCheckAttributeDefinition, ValueStream, VersionLabel, Violation, Workflow, WorkflowTransition, Workitem, WorkitemPriority, WorkitemRisk };
5566
+ export { ASSET_STATE_CODES, AgilityApiClient, ApiError, AttachmentUploadError, BatchRecordError, BatchSendError, CommandFailureError, INLINE_LIMIT, INVERSE, NUMBER_ROOTS, CHUNK as RESOLVE_CHUNK, Schema, TypeCache, UNGUARDABLE_TYPES, UnguardableError, UsageError, WrappedError, assetApi, assetStateOf, attachment, createFetchTransport, describe as describeBatch, fields, guard, importantName, isAssetNumber, isOidToken, kindOf, loc2, meta, momentless, namesOf, parseOid, parseViolation, queryV1, resolveNumbers, resolveRef, rest1, reverseOf, reversible, runBatch, select, sendGuarded, snapshot, stampsOf, toOid, touchedBy, typeOfOid, unguardable };
5567
+ export type { Access, Actual, Allocation, Application, Asset, AssetApiResponse, AssetChangedEventDefinition, AssetCreatedEventDefinition, AssetDocument, AssetNumberAttributeDefinition, AssetStateValue, AssetType, AssetTypeMap, AssetTypeName, AssetTypeToken, AssetsDocument, Attachment, AddOptions as AttachmentAddOptions, AttachmentCategory, AttachmentInfo, AttributeAddedEventDefinition, AttributeChangedEventDefinition, AttributeDefinition, AttributeLookup, AttributeRemovedEventDefinition, AttributeTokenRef, AttributeType, AttributeValue, BaseAsset, BatchOptions, Budget, BuildProject, BuildRun, BuildSource, BuildStatus, Bundle, BusinessRule, Bytes, CalendarEvent, CalendarEventCategory, Capacity, ChangeSet, ClassOfService, ClientConfig, ClientOptions, Command, CommandBody, CommandFailureDetail, CommandValue, Community, Concept, ConcreteAssetTypeName, ConditionalOptions, Conversation, CreateBody, CreateType, CredentialsAttributeDefinition, CustomAttributes, CustomList, DateString, DefaultRule, Defect, DefectResolution, DefectType, Delivery, DeliveryCategory, Described, EmbeddedImage$1 as EmbeddedImage, Environment, Epic, EpicCategory, EpicPriority, EpicStatus, ErrorKind, ExecuteBody, ExecuteSecurityCheckAttributeDefinition, Expression, ExpressionImage, ExpressionSpace, ExternalAction, ExternalActionInvocation, FetchTransportConfig, FieldsOf, From, Goal, GoalCategory, GoalPriority, Grant, GuardedResult, HierarchyRelationDefinition, Idea, IdeaCategory, IdeaChangeSet, IdeaComment, IdeaForum, IdeaStatus, IdeaUser, IdeasUserCache, Image, Issue, IssueCategory, IssuePriority, IssueResolution, IssueStatus, KeyResult, KeyResultCommitment, KeyResultUnit, Label, Link, LinkCategory, List, Localizations, LocalizeOptions, ManyToManyRelationDefinition, Me, Member, MemberLabel, Message, MessageReceipt, Metamodel, Milestone, MilestoneCategory, MultivalueAttributeDefinition, NameLookupFailure, Named, NoteCategory, Oid, OidParts, Okr, OkrObjective, OkrSession, OneToManyRelationDefinition, OperationExecutedEventDefinition, OperationResult, Outcome, Page, PagesOptions, PasswordAttributeDefinition, Phase, PlanningLevel, PlanningRoom, PrimaryWorkitem, PrincipalAttributeDefinition, Publication, QueryBody, QueryRejection, ReadOptions, ReadParams, ReadResult, Receipt, Ref, RegressionPlan, RegressionSuite, RegressionTest, RegressionTestStatus, Release, Request, RequestBody, RequestCategory, RequestOptions, RequestPriority, RequestResolution, RequestStatus, Resolution, ResolvedAsset, ResponseType, Retrospective, RetrospectivePrompt, RetrospectiveTopic, Reverse, Roadmap, Role, Room, RowContext, RowOf, RowsOf, SavedView, Schedule, Scheme, Scope, ScopeLabel, ScopeStatus, SelectKey, SelectPath, SelectValue, Selected, SendOptions, SimpleAttributeDefinition, State, Status, Story, StoryCategory, StorySource, StoryStatus, StrategicTheme, StrategicThemeLevel, Subscription, SubscriptionTerm, SyntheticAttributeDefinition, Tagged, Task, TaskCategory, TaskSource, TaskStatus, Team, TeamRoom, TeamWorkflow, Template, Test, TestCategory, TestRun, TestSet, TestStatus, TestSuite, Theme, ThemeCategory, ThemeLabel, ThemeSource, ThemeStatus, Timebox, Timesheet, Topic, Transport, TriggerType, TypeOf, UnauthorizedContext, UnauthorizedDecision, Unguardable, UpdateBody, UpdateSecurityCheckAttributeDefinition, ValueStream, VersionLabel, Violation, Workflow, WorkflowTransition, Workitem, WorkitemPriority, WorkitemRisk };