@pepys/api 0.0.1 → 0.1.1

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,28 +1,33 @@
1
- import type { Result } from '@pepys/kit';
2
- import type { StoreReader } from './store-reader.ts';
1
+ import type { ConsumerDeclaration, Result, StoreReader, StoreReaderFailure } from '@pepys/kit';
2
+ import { sql } from 'kysely';
3
+ import { z } from 'zod';
3
4
 
4
5
  interface Offset {
5
6
  stream: string;
6
7
  lastSeqNum: number;
7
8
  }
8
9
 
10
+ const offsetRowSchema = z.object({ stream: z.string(), last_seq_num: z.number() });
11
+ const offsetRowsSchema = z.object({ rows: z.array(offsetRowSchema) });
12
+
13
+ // The last sequence number the host applied from each stream the consumer reads.
9
14
  export async function readOffsets(
10
15
  store: StoreReader,
11
- consumerName: string,
12
- ): Promise<Result<Offset[], { reason: 'no-current-version' }>> {
13
- const result = await store.withConsumer(consumerName, (transaction) =>
14
- transaction
15
- .selectFrom('offsets')
16
- .select(['stream', 'last_seq_num'])
17
- .orderBy('stream')
18
- .execute(),
16
+ consumer: ConsumerDeclaration,
17
+ ): Promise<Result<Offset[], StoreReaderFailure>> {
18
+ const table = sql.table(`${consumer.name}.offsets`);
19
+
20
+ const result = await store.withConsumers([consumer], (db) =>
21
+ sql`select stream, last_seq_num from ${table} order by stream`.execute(db),
19
22
  );
20
23
 
21
24
  if (!result.ok) {
22
25
  return result;
23
26
  }
24
27
 
25
- const offsets = result.value.map((row) => ({ stream: row.stream, lastSeqNum: row.last_seq_num }));
28
+ const offsets = offsetRowsSchema
29
+ .parse(result.value)
30
+ .rows.map((row) => ({ stream: row.stream, lastSeqNum: row.last_seq_num }));
26
31
 
27
32
  return { ok: true, value: offsets };
28
33
  }
@@ -0,0 +1,8 @@
1
+ // Code unit order, as the default sort and SQLite's binary collation give, not the locale's.
2
+ export function compareText(first: string, second: string): number {
3
+ if (first === second) {
4
+ return 0;
5
+ }
6
+
7
+ return first < second ? -1 : 1;
8
+ }
@@ -1,33 +0,0 @@
1
- import type { StreamOffset } from '@pepys/kit';
2
-
3
- export type ChangeMessage =
4
- | {
5
- kind: 'change';
6
- type: string;
7
- key: string;
8
- value: unknown;
9
- oldValue: unknown;
10
- operation: 'insert' | 'update' | 'delete';
11
- }
12
- | { kind: 'snapshot-start' }
13
- | { kind: 'snapshot-end' };
14
-
15
- export interface FeedStream {
16
- consumer: string;
17
- generation: number;
18
- }
19
-
20
- export type FeedPosition = StreamOffset | -1 | 'now';
21
-
22
- export type FeedRead =
23
- | { kind: 'messages'; messages: readonly ChangeMessage[]; next: StreamOffset; atTail: boolean }
24
- | { kind: 'closed'; currentGeneration: number }
25
- | { kind: 'gone'; snapshotAt: StreamOffset };
26
-
27
- export interface ChangeFeed {
28
- read: (
29
- stream: FeedStream,
30
- from: FeedPosition,
31
- mode: 'catch-up' | 'long-poll',
32
- ) => Promise<FeedRead>;
33
- }
@@ -1,10 +0,0 @@
1
- import type { ClientID, GrantID } from '@pepys/kit';
2
-
3
- export type Scope = 'read' | 'write';
4
-
5
- export interface Principal {
6
- client: ClientID;
7
- clientName: string;
8
- grant: GrantID;
9
- scopes: readonly Scope[];
10
- }
@@ -1,23 +0,0 @@
1
- import type { ConsumerDeclaration, EntityIDParts, EntityViewDeclaration } from '@pepys/kit';
2
-
3
- export interface EntityConsumer {
4
- consumer: ConsumerDeclaration;
5
- entityView: EntityViewDeclaration;
6
- }
7
-
8
- export function findEntityConsumer(
9
- consumers: readonly ConsumerDeclaration[],
10
- parts: EntityIDParts,
11
- ): EntityConsumer | undefined {
12
- const kind = `${parts.source}:${parts.kind}`;
13
-
14
- for (const consumer of consumers) {
15
- const entityView = consumer.entityViews.find((view) => view.kind === kind);
16
-
17
- if (entityView !== undefined) {
18
- return { consumer, entityView };
19
- }
20
- }
21
-
22
- return undefined;
23
- }
@@ -1,6 +0,0 @@
1
- import { connect } from '@tursodatabase/database';
2
- import type { Database } from '@tursodatabase/database';
3
-
4
- export function openConsumerDatabase(path: string): Promise<Database> {
5
- return connect(path, { readonly: true, experimental: ['multiprocess_wal'] });
6
- }
@@ -1,13 +0,0 @@
1
- import type { Result } from '@pepys/kit';
2
- import type { Selectable } from 'kysely';
3
- import type { ConsumerDB, StoreReader } from './store-reader.ts';
4
-
5
- type PullRequestRow = Selectable<ConsumerDB['github_pull_request']>;
6
-
7
- export function readPullRequests(
8
- store: StoreReader,
9
- ): Promise<Result<PullRequestRow[], { reason: 'no-current-version' }>> {
10
- return store.withConsumer('github_pull_request', (transaction) =>
11
- transaction.selectFrom('github_pull_request').selectAll().orderBy('id').execute(),
12
- );
13
- }
@@ -1,37 +0,0 @@
1
- import type { Result } from '@pepys/kit';
2
- import type { DB } from '@pepys/schema';
3
- import type { Transaction } from 'kysely';
4
-
5
- interface EntityViewRow {
6
- id: string;
7
- kind: string;
8
- title: string;
9
- url: string;
10
- actor: string | null;
11
- updated_at: string;
12
- }
13
-
14
- // the host creates these two tables in every consumer file, beside the consumer's own
15
- interface OffsetRow {
16
- stream: string;
17
- last_seq_num: number;
18
- }
19
-
20
- interface ChangeLogRow {
21
- batch: number;
22
- changes: string;
23
- }
24
-
25
- export type ConsumerDB = DB & {
26
- entity: EntityViewRow;
27
- offsets: OffsetRow;
28
- change_log: ChangeLogRow;
29
- };
30
-
31
- export interface StoreReader {
32
- withConsumer: <Value>(
33
- consumerName: string,
34
- work: (transaction: Transaction<ConsumerDB>) => Promise<Value>,
35
- ) => Promise<Result<Value, { reason: 'no-current-version' }>>;
36
- close: () => Promise<void>;
37
- }