@hollware/server 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,26 +1,6 @@
1
1
  import { AcknowledgedWarning, EntryDocument, EntryLookup, EntryRef, HollwareConfig, OperationByName, OperationName, ResolvedSite, Scope, Verdict, describeSite, getEntry, getTranslations, listEntries } from "@hollware/core";
2
2
  import * as z from "zod";
3
3
  import { WorkerEntrypoint } from "cloudflare:workers";
4
- //#region src/auth/types.d.ts
5
- /**
6
- * Who calls an operation. The gateway turns each request into a principal before any handler
7
- * runs, and the handlers check their scopes against it at call time (ADR-019).
8
- */
9
- type Principal = {
10
- /** A personal token. */
11
- readonly kind: 'token';
12
- readonly userId: string;
13
- readonly tokenId: string;
14
- /** The site the token belongs to; it never reaches another one. */
15
- readonly site: string;
16
- /** The token's own scopes intersected with those of its user's role, as of now. */
17
- readonly scopes: readonly Scope[];
18
- } | {
19
- /** A Worker of the same account, over the RPC binding: it reads published content. */
20
- readonly kind: 'binding';
21
- readonly scopes: readonly ['content:read'];
22
- };
23
- //#endregion
24
4
  //#region src/ports.d.ts
25
5
  /**
26
6
  * The ports of the operation handlers: what they need from the world, as interfaces. The D1
@@ -142,6 +122,32 @@ type WriteRefusal = {
142
122
  readonly bytes: number;
143
123
  readonly limit: number;
144
124
  };
125
+ /** A scheduled publication, as the cron trigger reads it. */
126
+ interface StoredSchedule {
127
+ readonly entryId: string;
128
+ readonly scheduledAt: string;
129
+ /** The version the entry had once scheduled; another one means it changed since. */
130
+ readonly version: number;
131
+ readonly acknowledged: readonly AcknowledgedWarning[];
132
+ readonly actor: Actor;
133
+ }
134
+ /** One entry of a publication: what `publish` and `publishGroup` write for it. */
135
+ interface PublishWrite {
136
+ readonly entryId: string;
137
+ readonly expectedVersion: number;
138
+ readonly verdict: Verdict;
139
+ readonly acknowledged: readonly AcknowledgedWarning[];
140
+ readonly actor: Actor;
141
+ /** What orders the entry in published listings. */
142
+ readonly sortKey: string;
143
+ /** The event of the publication, written to the outbox in the same batch (ADR-025). */
144
+ readonly event?: OutboxEvent | null;
145
+ }
146
+ /** An event for the outbox: its id and what subscribers get, as JSON. */
147
+ interface OutboxEvent {
148
+ readonly id: string;
149
+ readonly payload: string;
150
+ }
145
151
  interface ContentStore {
146
152
  /** The entry with that collection, locale and slug, in the given view, or `null`. */
147
153
  findEntry(site: string, ref: EntryRef, view: View): Promise<EntryView | null>;
@@ -186,22 +192,44 @@ interface ContentStore {
186
192
  * Publishes the head revision, if the entry is still at `expectedVersion`, and appends the
187
193
  * publication with its verdict and acknowledged warnings.
188
194
  */
189
- publish(site: string, write: {
195
+ publish(site: string, write: PublishWrite): Promise<{
196
+ readonly outcome: 'published';
197
+ readonly view: EntryView;
198
+ } | WriteRefusal>;
199
+ /**
200
+ * Publishes the head revisions of a group of entries in one batch, all or none (ADR-024): every
201
+ * entry must still be at its `expectedVersion`. A refusal names the entry that caused it.
202
+ */
203
+ publishGroup(site: string, writes: readonly PublishWrite[]): Promise<{
204
+ readonly outcome: 'published';
205
+ readonly views: readonly EntryView[];
206
+ } | (WriteRefusal & {
207
+ readonly entryId: string;
208
+ })>;
209
+ /**
210
+ * Schedules the publication of an entry that is not published, if it is still at
211
+ * `expectedVersion`: the entry becomes `scheduled` at the next version, and its schedule keeps
212
+ * the acknowledged warnings and the actor for the cron trigger (ADR-025).
213
+ */
214
+ schedule(site: string, write: {
190
215
  readonly entryId: string;
191
216
  readonly expectedVersion: number;
192
- readonly verdict: Verdict;
217
+ readonly scheduledAt: string;
193
218
  readonly acknowledged: readonly AcknowledgedWarning[];
194
219
  readonly actor: Actor;
195
- /** What orders the entry in published listings. */
196
- readonly sortKey: string;
197
220
  }): Promise<{
198
- readonly outcome: 'published';
221
+ readonly outcome: 'scheduled';
199
222
  readonly view: EntryView;
200
223
  } | WriteRefusal>;
224
+ /** The schedules whose time has come, at most 50, oldest first. */
225
+ dueSchedules(site: string, now: string): Promise<readonly StoredSchedule[]>;
226
+ /** Takes a scheduled entry back to a draft and drops its schedule. */
227
+ cancelSchedule(site: string, entryId: string): Promise<void>;
201
228
  /** Takes the entry off the public site and appends the unpublish. */
202
229
  unpublish(site: string, write: {
203
230
  readonly entryId: string;
204
231
  readonly actor: Actor;
232
+ readonly event?: OutboxEvent | null;
205
233
  }): Promise<{
206
234
  readonly outcome: 'unpublished';
207
235
  readonly view: EntryView;
@@ -212,6 +240,45 @@ interface Clock {
212
240
  now(): Date;
213
241
  }
214
242
  //#endregion
243
+ //#region src/events/run.d.ts
244
+ /** A message of the events Queue: the site and the id of an outbox row. */
245
+ interface EventMessage {
246
+ readonly site: string;
247
+ readonly id: string;
248
+ }
249
+ /** The part of a Queue binding that sends. */
250
+ interface EventQueue {
251
+ sendBatch(messages: Iterable<{
252
+ readonly body: EventMessage;
253
+ }>): Promise<unknown>;
254
+ }
255
+ /** The part of a Queue message the consumer uses; its body is checked before use. */
256
+ interface EventDelivery {
257
+ readonly body: unknown;
258
+ ack(): void;
259
+ retry(): void;
260
+ }
261
+ //#endregion
262
+ //#region src/auth/types.d.ts
263
+ /**
264
+ * Who calls an operation. The gateway turns each request into a principal before any handler
265
+ * runs, and the handlers check their scopes against it at call time (ADR-019).
266
+ */
267
+ type Principal = {
268
+ /** A personal token. */
269
+ readonly kind: 'token';
270
+ readonly userId: string;
271
+ readonly tokenId: string;
272
+ /** The site the token belongs to; it never reaches another one. */
273
+ readonly site: string;
274
+ /** The token's own scopes intersected with those of its user's role, as of now. */
275
+ readonly scopes: readonly Scope[];
276
+ } | {
277
+ /** A Worker of the same account, over the RPC binding: it reads published content. */
278
+ readonly kind: 'binding';
279
+ readonly scopes: readonly ['content:read'];
280
+ };
281
+ //#endregion
215
282
  //#region src/ops/types.d.ts
216
283
  /**
217
284
  * The handlers of the operations (ADR-017): one per spec of `@hollware/core`, paired by type,
@@ -228,6 +295,11 @@ interface OperationContext {
228
295
  /** What the client said about itself; writes record it as the actor's meta. */
229
296
  readonly client: Readonly<Record<string, unknown>> | null;
230
297
  readonly requestId: string;
298
+ /**
299
+ * Called with the ids of the events that a write committed to the outbox, so that they reach
300
+ * the Queue now rather than at the next sweep of the cron trigger (ADR-025). Absent in tests.
301
+ */
302
+ readonly notify?: (eventIds: readonly string[]) => void;
231
303
  }
232
304
  /** The handler of one operation: its parsed input in, its output out. */
233
305
  type OperationHandler<Name extends OperationName> = (input: z.output<OperationByName<Name>['input']>, context: OperationContext) => Promise<z.output<OperationByName<Name>['output']>>;
@@ -266,6 +338,8 @@ export interface HollwareEnv {
266
338
  * Origin the Worker answers; without it, every request fails.
267
339
  */
268
340
  readonly HOLLWARE_PUBLIC_URL: string;
341
+ /** The Queue of publication events (ADR-025); without it, the cron trigger delivers them. */
342
+ readonly EVENTS?: EventQueue;
269
343
  }
270
344
  type Output<Spec extends {
271
345
  output: z.ZodType;
@@ -294,6 +368,12 @@ export interface HollwareRpc {
294
368
  export interface HollwareWorker {
295
369
  /** MCP at `/mcp`, and the other routes of the gateway. */
296
370
  readonly fetch: (request: Request, env: HollwareEnv, ctx: ExecutionContext) => Promise<Response>;
371
+ /** The consumer of the events Queue (`queues.consumers` in wrangler.jsonc). */
372
+ readonly queue: (batch: {
373
+ readonly messages: readonly EventDelivery[];
374
+ }, env: HollwareEnv, ctx: ExecutionContext) => Promise<void>;
375
+ /** The cron trigger of the project (`triggers.crons` in wrangler.jsonc, every minute). */
376
+ readonly scheduled: (controller: ScheduledController, env: HollwareEnv, ctx: ExecutionContext) => Promise<void>;
297
377
  /** The RPC entrypoint, for the user's Worker to export under the name `Hollware`. */
298
378
  readonly Hollware: new (ctx: ExecutionContext, env: HollwareEnv) => WorkerEntrypoint<HollwareEnv> & HollwareRpc;
299
379
  }
@@ -306,4 +386,4 @@ export type CreateHollware = (config: HollwareConfig) => HollwareWorker;
306
386
  */
307
387
  export declare const createHollware: CreateHollware;
308
388
  //#endregion
309
- export type { Actor, Clock, ContentStore, EntrySummaryView, EntryView, Handlers, ListQuery, NewRevision, OperationContext, OperationHandler, Principal, RevisionSummary, StoredEntry, StoredPublication, StoredRevision, View, WriteRefusal };
389
+ export type { Actor, Clock, ContentStore, EntrySummaryView, EntryView, EventMessage, Handlers, ListQuery, NewRevision, OperationContext, OperationHandler, OutboxEvent, Principal, PublishWrite, RevisionSummary, StoredEntry, StoredPublication, StoredRevision, StoredSchedule, View, WriteRefusal };