@nohead/sdk 0.2.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.
@@ -1,10 +1,10 @@
1
- import { Resource } from "./resource.js";
1
+ import { listQuery, Resource } from "./resource.js";
2
2
  /** Collections of the key's project. `collection` is an ID or slug. */
3
3
  export class Collections extends Resource {
4
4
  schemaChanges = new SchemaChanges(this.core);
5
5
  searchIndex = new SearchIndexes(this.core);
6
6
  list(params = {}, options) {
7
- return this.core.paginate("collections_list", { query: params }, options);
7
+ return this.core.paginate("collections_list", { query: listQuery(params, ["deleted"]) }, options);
8
8
  }
9
9
  get(collection, options) {
10
10
  return this.core.request("collections_get", { path: { collection_id: collection } }, options);
@@ -16,7 +16,10 @@ export class Collections extends Resource {
16
16
  update(collection, params, options) {
17
17
  return this.core.request("collections_update", { path: { collection_id: collection }, body: params }, options);
18
18
  }
19
- /** Soft-deletes the collection and its records for 30 days. */
19
+ /**
20
+ * Soft-deletes the collection and its records: `restore` brings them back
21
+ * until its `purge_after`.
22
+ */
20
23
  delete(collection, options) {
21
24
  return this.core.request("collections_delete", { path: { collection_id: collection } }, options);
22
25
  }
@@ -52,11 +55,17 @@ export class SearchIndexes extends Resource {
52
55
  /** Fields of a collection. `field` is a field ID (`fld_…`). */
53
56
  export class Fields extends Resource {
54
57
  list(collection, params = {}, options) {
55
- return this.core.paginate("fields_list", { path: { collection_id: collection }, query: params }, options);
58
+ return this.core.paginate("fields_list", {
59
+ path: { collection_id: collection },
60
+ query: listQuery(params, ["deleted"]),
61
+ }, options);
56
62
  }
57
63
  create(collection, params, options) {
58
64
  return this.core.request("fields_create", { path: { collection_id: collection }, body: params }, options);
59
65
  }
66
+ get(field, options) {
67
+ return this.core.request("fields_get", { path: { field_id: field } }, options);
68
+ }
60
69
  /**
61
70
  * Renames, describes or loosens a field. Changes that rewrite record
62
71
  * values (type, `multiple`, tighter rules) are `migrate`.
@@ -64,14 +73,21 @@ export class Fields extends Resource {
64
73
  update(field, params, options) {
65
74
  return this.core.request("fields_update", { path: { field_id: field }, body: params }, options);
66
75
  }
67
- /** Soft-deletes the field: its values return with `restore` for 30 days. */
76
+ /**
77
+ * Soft-deletes the field: its values come back with `restore` until its
78
+ * `purge_after`.
79
+ */
68
80
  delete(field, options) {
69
81
  return this.core.request("fields_delete", { path: { field_id: field } }, options);
70
82
  }
71
83
  restore(field, options) {
72
84
  return this.core.request("fields_restore", { path: { field_id: field } }, options);
73
85
  }
74
- /** Puts the collection's fields in this order. */
86
+ /** The collection's active fields, in order. */
87
+ order(collection, options) {
88
+ return this.core.request("fields_get_order", { path: { collection_id: collection } }, options);
89
+ }
90
+ /** Puts the collection's fields in this order; lists every active field once. */
75
91
  reorder(collection, params, options) {
76
92
  return this.core.request("fields_reorder", { path: { collection_id: collection }, body: params }, options);
77
93
  }
@@ -1,20 +1,27 @@
1
1
  import type { APIPromise, PagePromise } from "../api-promise.ts";
2
2
  import type { RequestOptions } from "../core.ts";
3
- import type { Webhook, WebhookCreate, WebhookDelivery, WebhookDeliveryDetail, WebhookUpdate, WebhookWithSecret } from "../generated/types.gen.ts";
4
- import type { DeliveryListParams, ListParams, RecordData } from "../types.ts";
3
+ import type { Webhook, WebhookCreate, WebhookDelivery, WebhookDeliveryDetail, WebhookSecret, WebhookSecretWithValue, WebhookUpdate, WebhookWithSecret } from "../generated/types.gen.ts";
4
+ import type { DeletedListParams, DeliveryListParams, ListParams, RecordData } from "../types.ts";
5
5
  import { type UnwrapOptions, type WebhookEvent, type WebhookHeaders } from "../webhooks.ts";
6
6
  import { Resource } from "./resource.ts";
7
7
  /** Webhooks of the key's project. `webhook` is a webhook ID (`wh_…`). */
8
8
  export declare class Webhooks extends Resource {
9
9
  readonly deliveries: Deliveries;
10
- list(params?: ListParams, options?: RequestOptions): PagePromise<Webhook>;
10
+ readonly secrets: Secrets;
11
+ list(params?: DeletedListParams, options?: RequestOptions): PagePromise<Webhook>;
11
12
  get(webhook: string, options?: RequestOptions): APIPromise<Webhook>;
12
13
  /** Subscribes a URL. The response is the only time `secret` is shown. */
13
14
  create(params: WebhookCreate, options?: RequestOptions): APIPromise<WebhookWithSecret>;
14
15
  update(webhook: string, params: WebhookUpdate, options?: RequestOptions): APIPromise<Webhook>;
16
+ /** Soft-deletes the webhook: `restore` brings it back until its `purge_after`. */
15
17
  delete(webhook: string, options?: RequestOptions): APIPromise<Webhook>;
16
- /** A new signing secret; the old one stops working at once. */
17
- rotateSecret(webhook: string, options?: RequestOptions): APIPromise<WebhookWithSecret>;
18
+ restore(webhook: string, options?: RequestOptions): APIPromise<Webhook>;
19
+ /**
20
+ * A new signing secret (`secret`, shown only here). The ones before it
21
+ * keep signing for 24 hours, so receivers can switch without rejecting
22
+ * deliveries; `secrets.retire` ends one sooner.
23
+ */
24
+ rotateSecret(webhook: string, options?: RequestOptions): APIPromise<WebhookSecretWithValue>;
18
25
  /** Sends a `webhook.test` event to the URL. */
19
26
  test(webhook: string, options?: RequestOptions): APIPromise<WebhookDelivery>;
20
27
  /**
@@ -27,6 +34,13 @@ export declare class Webhooks extends Resource {
27
34
  export declare class Deliveries extends Resource {
28
35
  list(webhook: string, params?: DeliveryListParams, options?: RequestOptions): PagePromise<WebhookDelivery>;
29
36
  get(delivery: string, options?: RequestOptions): APIPromise<WebhookDeliveryDetail>;
30
- /** Sends the event again. */
37
+ /** Sends the event again now, as a new attempt. */
31
38
  retry(delivery: string, options?: RequestOptions): APIPromise<WebhookDelivery>;
32
39
  }
40
+ /** A webhook's signing secrets. `secret` is a secret ID (`whs_…`). */
41
+ export declare class Secrets extends Resource {
42
+ /** Those signing deliveries now, oldest first, without their values. */
43
+ list(webhook: string, params?: ListParams, options?: RequestOptions): PagePromise<WebhookSecret>;
44
+ /** Stops signing with it now. The newest can't be retired: rotate first. */
45
+ retire(secret: string, options?: RequestOptions): APIPromise<WebhookSecret>;
46
+ }
@@ -1,10 +1,11 @@
1
1
  import { unwrapWebhook, } from "../webhooks.js";
2
- import { Resource } from "./resource.js";
2
+ import { listQuery, Resource } from "./resource.js";
3
3
  /** Webhooks of the key's project. `webhook` is a webhook ID (`wh_…`). */
4
4
  export class Webhooks extends Resource {
5
5
  deliveries = new Deliveries(this.core);
6
+ secrets = new Secrets(this.core);
6
7
  list(params = {}, options) {
7
- return this.core.paginate("webhooks_list", { query: params }, options);
8
+ return this.core.paginate("webhooks_list", { query: listQuery(params, ["deleted"]) }, options);
8
9
  }
9
10
  get(webhook, options) {
10
11
  return this.core.request("webhooks_get", { path: { webhook_id: webhook } }, options);
@@ -16,10 +17,18 @@ export class Webhooks extends Resource {
16
17
  update(webhook, params, options) {
17
18
  return this.core.request("webhooks_update", { path: { webhook_id: webhook }, body: params }, options);
18
19
  }
20
+ /** Soft-deletes the webhook: `restore` brings it back until its `purge_after`. */
19
21
  delete(webhook, options) {
20
22
  return this.core.request("webhooks_delete", { path: { webhook_id: webhook } }, options);
21
23
  }
22
- /** A new signing secret; the old one stops working at once. */
24
+ restore(webhook, options) {
25
+ return this.core.request("webhooks_restore", { path: { webhook_id: webhook } }, options);
26
+ }
27
+ /**
28
+ * A new signing secret (`secret`, shown only here). The ones before it
29
+ * keep signing for 24 hours, so receivers can switch without rejecting
30
+ * deliveries; `secrets.retire` ends one sooner.
31
+ */
23
32
  rotateSecret(webhook, options) {
24
33
  return this.core.request("webhooks_rotate_secret", { path: { webhook_id: webhook } }, options);
25
34
  }
@@ -38,13 +47,24 @@ export class Webhooks extends Resource {
38
47
  /** Delivery attempts of a webhook's events. */
39
48
  export class Deliveries extends Resource {
40
49
  list(webhook, params = {}, options) {
41
- return this.core.paginate("webhook_deliveries_list", { path: { webhook_id: webhook }, query: params }, options);
50
+ return this.core.paginate("webhook_deliveries_list", { path: { webhook_id: webhook }, query: listQuery(params, ["status"]) }, options);
42
51
  }
43
52
  get(delivery, options) {
44
53
  return this.core.request("webhook_deliveries_get", { path: { delivery_id: delivery } }, options);
45
54
  }
46
- /** Sends the event again. */
55
+ /** Sends the event again now, as a new attempt. */
47
56
  retry(delivery, options) {
48
57
  return this.core.request("webhook_deliveries_retry", { path: { delivery_id: delivery } }, options);
49
58
  }
50
59
  }
60
+ /** A webhook's signing secrets. `secret` is a secret ID (`whs_…`). */
61
+ export class Secrets extends Resource {
62
+ /** Those signing deliveries now, oldest first, without their values. */
63
+ list(webhook, params = {}, options) {
64
+ return this.core.paginate("webhook_secrets_list", { path: { webhook_id: webhook }, query: params }, options);
65
+ }
66
+ /** Stops signing with it now. The newest can't be retired: rotate first. */
67
+ retire(secret, options) {
68
+ return this.core.request("webhook_secrets_retire", { path: { secret_id: secret } }, options);
69
+ }
70
+ }
package/dist/types.d.ts CHANGED
@@ -10,19 +10,47 @@ export type * from "./generated/schemas.gen.ts";
10
10
  export type NoheadRecord<D = G.RecordData> = Omit<G.Record, "data"> & {
11
11
  data: D;
12
12
  };
13
+ /**
14
+ * A draft whose `data` (the record's values as they read after the merge)
15
+ * has the shape `D`, as on `NoheadRecord<D>`. Also `Nohead.Draft`.
16
+ */
17
+ export type NoheadDraft<D = G.RecordData> = Omit<G.Draft, "data"> & {
18
+ data: D;
19
+ };
13
20
  /** Field values to write: `null` clears a field. */
14
21
  export type RecordDataUpdate<D> = {
15
22
  [K in keyof D]?: D[K] | null;
16
23
  };
17
24
  export type FilterValue = string | number | boolean | Date;
18
25
  /**
19
- * Equality filters: `{ status: "published", author: "rec_…" }`. For fields
20
- * with several values a filter means "contains".
26
+ * Operators for one key. `ne` matches records without a value; on fields
27
+ * with several values `eq`, `ne` and `in` mean contains, does not contain and
28
+ * contains any of. Ranges take numbers and dates (`"today"`, `"now"`, or a
29
+ * day, which covers that day in the field's time zone).
30
+ */
31
+ export interface FilterOperators<V = FilterValue> {
32
+ eq?: V;
33
+ ne?: V;
34
+ gt?: V;
35
+ gte?: V;
36
+ lt?: V;
37
+ lte?: V;
38
+ /** Any of these (up to 100). */
39
+ in?: V[];
40
+ /** Has a value (`true`) or has none (`false`). */
41
+ exists?: boolean;
42
+ }
43
+ /**
44
+ * Filters, combined with AND: a value to equal, or operators, e.g.
45
+ * `{ published_at: { exists: true }, price: { lt: 50 }, category: { in: ["shoes", "bags"] } }`.
46
+ * `published_at: { exists }` says whether records are published; record
47
+ * lists and counts also filter `created_at`, `updated_at` and `published_at`
48
+ * by range. `deleted: true` lists deleted records instead.
21
49
  */
22
50
  export interface RecordFilter {
23
- status?: "draft" | "published";
51
+ published_at?: FilterOperators<string | Date>;
24
52
  deleted?: boolean;
25
- [apiKey: string]: FilterValue | undefined;
53
+ [apiKey: string]: FilterValue | FilterOperators | undefined;
26
54
  }
27
55
  export type RecordSort = NonNullable<NonNullable<G.RecordsListData["query"]>["sort"]>;
28
56
  export interface ListParams {
@@ -37,9 +65,9 @@ export interface RecordListParams extends ListParams {
37
65
  /** Relation or asset fields to embed under `expanded` (at most 5). */
38
66
  expand?: string[];
39
67
  }
68
+ /** A deleted record is returned too, with `deleted_at` and `purge_after`. */
40
69
  export interface RecordGetParams {
41
70
  expand?: string[];
42
- include_deleted?: boolean;
43
71
  }
44
72
  export interface RecordCreateParams<D = G.RecordData> {
45
73
  data: D;
@@ -47,18 +75,44 @@ export interface RecordCreateParams<D = G.RecordData> {
47
75
  export interface RecordUpdateParams<D = G.RecordData> {
48
76
  data: RecordDataUpdate<D>;
49
77
  }
78
+ /** `data` over the record's values, or with `from_revision`, an earlier revision's. */
79
+ export interface DraftCreateParams<D = G.RecordData> {
80
+ data?: RecordDataUpdate<D>;
81
+ from_revision?: number;
82
+ }
83
+ export interface DraftUpdateParams<D = G.RecordData> {
84
+ data: RecordDataUpdate<D>;
85
+ }
86
+ export interface DraftGetParams {
87
+ /** Relation or asset fields to embed under `expanded` (at most 5). */
88
+ expand?: string[];
89
+ }
90
+ export interface DraftListParams extends ListParams {
91
+ /** One record's draft, or several records' (up to 100). */
92
+ record_id?: string | string[];
93
+ sort?: "updated_at" | "-updated_at";
94
+ }
95
+ export interface DraftScheduleParams {
96
+ /** When to merge the draft: a future time. */
97
+ merge_at: string | Date;
98
+ }
50
99
  export interface RecordCountParams {
51
100
  filter?: RecordFilter;
52
101
  }
102
+ /** The whole schedule: a time left out is cleared, as `null` is. */
53
103
  export interface RecordScheduleParams {
54
- /** A future time, or `null` for none. Omitted keys keep their value. */
104
+ /** A future time, or `null` for none. */
55
105
  publish_at?: string | Date | null;
56
106
  unpublish_at?: string | Date | null;
57
107
  }
58
- export type RecordBulkParams = G.BulkRecordsRequest;
108
+ export interface ScheduledChangeListParams extends ListParams {
109
+ /** Soonest first by default (`at`). */
110
+ sort?: "at" | "-at";
111
+ }
112
+ export type RecordBulkParams = G.RecordBatchRequest;
59
113
  export type RecordDiffParams = NonNullable<G.RecordsDiffData["query"]>;
60
114
  export interface RecordSearchParams extends ListParams {
61
- /** Needs `filterable` fields (status and timestamps always work). */
115
+ /** Needs `filterable` fields (`published_at: { exists }` always works). */
62
116
  filter?: RecordFilter;
63
117
  /** Needs a `sortable` field, e.g. `-published_at`; relevance otherwise. */
64
118
  sort?: string;
@@ -67,19 +121,36 @@ export interface RecordSearchParams extends ListParams {
67
121
  export interface ProjectSearchParams extends ListParams {
68
122
  /** Collection slugs or IDs to search in; every searchable one otherwise. */
69
123
  collections?: string[];
124
+ /** `{ published_at: { exists: true } }`: published records only (or unpublished, `false`). */
70
125
  filter?: {
71
- status?: "draft" | "published";
126
+ published_at?: {
127
+ exists: boolean;
128
+ };
72
129
  };
73
130
  }
131
+ /** A time range, e.g. `{ gte: "2026-10-01T00:00:00Z", lt: new Date() }`. */
132
+ export interface TimeRange {
133
+ gte?: string | Date;
134
+ gt?: string | Date;
135
+ lte?: string | Date;
136
+ lt?: string | Date;
137
+ }
138
+ /** Filters of a record's revisions, combined with AND. */
139
+ export interface RevisionFilter {
140
+ operation?: G.RecordRevisionOperation;
141
+ /** A user (`usr_…`) or API key (`key_…`). */
142
+ actor_id?: string;
143
+ created_at?: TimeRange;
144
+ }
74
145
  export interface RevisionListParams extends ListParams {
75
- filter?: NonNullable<G.RecordRevisionsListData["query"]>["filter"];
146
+ filter?: RevisionFilter;
76
147
  }
77
148
  export interface DryRunParams {
78
149
  /** Preview the change without making it. */
79
150
  dry_run?: boolean;
80
151
  }
81
152
  export interface DeletedListParams extends ListParams {
82
- /** List deleted items instead (they can be restored for 30 days). */
153
+ /** List deleted items instead (they can be restored until `purge_after`). */
83
154
  deleted?: boolean;
84
155
  }
85
156
  export interface AssetListParams extends DeletedListParams {
@@ -95,12 +166,28 @@ export interface SchemaParams {
95
166
  version?: number;
96
167
  }
97
168
  export type FieldMigrateParams = G.FieldMigrationRequest;
169
+ export interface FieldReorderParams {
170
+ /** Every active field of the collection, once each, in the new order. */
171
+ field_ids: string[];
172
+ }
98
173
  export type ImageUrlParams = NonNullable<G.AssetsImageUrlData["query"]>;
99
174
  export interface DeliveryListParams extends ListParams {
100
175
  status?: "pending" | "succeeded" | "failed";
101
176
  }
177
+ /** Filters of the activity log, combined with AND. */
178
+ export interface AuditEventFilter {
179
+ /** An event type, or a prefix with a trailing `.*` (`record.*`). */
180
+ type?: string;
181
+ /** What events are about (`record`, `field`…): one type, or any of several. */
182
+ resource_type?: string | string[];
183
+ resource_id?: string;
184
+ actor_type?: "user" | "api_key" | "system";
185
+ /** A user (`usr_…`) or API key (`key_…`). */
186
+ actor_id?: string;
187
+ created_at?: TimeRange;
188
+ }
102
189
  export interface AuditEventListParams extends ListParams {
103
- filter?: Omit<NonNullable<NonNullable<G.AuditEventsListForProjectData["query"]>["filter"]>, "project_id">;
190
+ filter?: AuditEventFilter;
104
191
  sort?: "id" | "-id";
105
192
  }
106
193
  /** The metadata of a search page: also an estimate of the total hits. */
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.2.0";
1
+ export declare const VERSION = "0.3.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = "0.2.0";
1
+ export const VERSION = "0.3.0";
@@ -1,35 +1,55 @@
1
- import type { Asset, Collection, SchemaChange, Webhook } from "./generated/types.gen.ts";
2
- import type { NoheadRecord, RecordData } from "./types.ts";
1
+ import type * as G from "./generated/types.gen.ts";
2
+ import type { NoheadDraft, NoheadRecord, RecordData } from "./types.ts";
3
3
  interface EventBase<Type extends string, Data> {
4
4
  id: string;
5
5
  object: "event";
6
6
  type: Type;
7
7
  created_at: string;
8
8
  project_id: string;
9
+ /** Who made the change. An integration that writes back can skip its own. */
10
+ actor: G.Actor;
11
+ /** The client the change came through, when known. */
12
+ via: G.Via | null;
9
13
  data: Data;
10
14
  }
11
- export type RecordEvent<D = RecordData> = EventBase<"record.created" | "record.updated" | "record.deleted" | "record.published" | "record.unpublished", {
12
- record: NoheadRecord<D>;
13
- revision: number;
14
- revision_id: string;
15
- }>;
16
- export type AssetEvent = EventBase<"asset.created" | "asset.deleted", {
17
- asset: Asset;
15
+ /** The event types that start with `prefix`. */
16
+ type TypesOf<Prefix extends string> = Extract<G.WebhookEventType, `${Prefix}.${string}`>;
17
+ /**
18
+ * A change to a record. `record` is the record as the change's revision left
19
+ * it, or as it is now for events without a revision (`record.scheduled`,
20
+ * `record.unscheduled`, `record.schedule_failed`, `record.redacted`); `null`
21
+ * once the record is purged.
22
+ */
23
+ export type RecordEvent<D = RecordData> = EventBase<TypesOf<"record">, Omit<G.RecordEventData, "record"> & {
24
+ record: NoheadRecord<D> | null;
18
25
  }>;
19
- export type SchemaChangedEvent = EventBase<"schema.changed", {
20
- collection: Collection;
21
- schema_change: SchemaChange;
26
+ /**
27
+ * A change to a draft. `draft` is the draft as it is now; `null` once merged
28
+ * or discarded, and while its record is deleted.
29
+ */
30
+ export type DraftEvent<D = RecordData> = EventBase<TypesOf<"draft">, Omit<G.DraftEventData, "draft"> & {
31
+ draft: NoheadDraft<D> | null;
22
32
  }>;
33
+ /** An asset as it is now; only its `id` and `object` once it is purged. */
34
+ export type AssetEvent = EventBase<TypesOf<"asset">, G.AssetEventData>;
35
+ /**
36
+ * A schema change: the collection as it left it, and the change; a field's
37
+ * events also name the field (`field_id`).
38
+ */
39
+ export type SchemaEvent = EventBase<Exclude<TypesOf<"collection" | "field">, "field.alias_removed">, G.SchemaEventData>;
40
+ /** A renamed field's old API key stopped answering before it expired. */
41
+ export type FieldAliasRemovedEvent = EventBase<"field.alias_removed", G.FieldAliasEventData>;
23
42
  /** Sent by `webhooks.test`. */
24
- export type WebhookTestEvent = EventBase<"webhook.test", {
25
- webhook: Webhook;
26
- }>;
43
+ export type WebhookTestEvent = EventBase<"webhook.test", G.WebhookTestEventData>;
27
44
  /** A webhook request's body, narrowed by `type`. */
28
- export type WebhookEvent<D = RecordData> = RecordEvent<D> | AssetEvent | SchemaChangedEvent | WebhookTestEvent;
45
+ export type WebhookEvent<D = RecordData> = RecordEvent<D> | DraftEvent<D> | AssetEvent | SchemaEvent | FieldAliasRemovedEvent | WebhookTestEvent;
29
46
  /** Request headers: a `Headers` object or a plain object (e.g. Node's). */
30
47
  export type WebhookHeaders = Headers | Record<string, string | string[] | undefined>;
31
48
  export interface UnwrapOptions {
32
- /** The webhook's signing secret (`whsec_…`). */
49
+ /**
50
+ * The webhook's signing secret (`whsec_…`). While a rotation overlaps,
51
+ * requests carry a signature for each secret, so either one verifies.
52
+ */
33
53
  secret: string;
34
54
  /** Seconds a timestamp may be off from now. Default 300. */
35
55
  tolerance?: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nohead/sdk",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Official TypeScript SDK for the Nohead API",
5
5
  "license": "MIT",
6
6
  "homepage": "https://nohead.io",
@@ -53,6 +53,7 @@
53
53
  "@eslint/js": "^10.0.1",
54
54
  "@hey-api/openapi-ts": "0.99.0",
55
55
  "@types/node": "^26.6.4",
56
+ "ajv": "^8.20.0",
56
57
  "eslint": "^10.12.0",
57
58
  "globals": "^17.13.0",
58
59
  "prettier": "^3.9.9",