@trypattern/sdk 0.1.33 → 0.1.34

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.
Files changed (45) hide show
  1. package/dist/app.d.ts +6 -2
  2. package/dist/app.js +6 -1
  3. package/dist/blocks.js +11 -3
  4. package/dist/bookings.d.ts +78 -0
  5. package/dist/bookings.js +7 -1
  6. package/dist/bookingsStore.d.ts +78 -0
  7. package/dist/cli/app.js +17 -2
  8. package/dist/cli/requests.d.ts +5 -0
  9. package/dist/cli/requests.js +115 -0
  10. package/dist/components/AppFrame.js +12 -2
  11. package/dist/components/MenuItems.d.ts +1 -0
  12. package/dist/components/MenuItems.js +13 -2
  13. package/dist/components/SegmentedControl.d.ts +1 -0
  14. package/dist/components/SegmentedControl.js +9 -2
  15. package/dist/components/Sidebar.d.ts +1 -0
  16. package/dist/components/Sidebar.js +18 -2
  17. package/dist/components/TableRow.d.ts +2 -1
  18. package/dist/components/TableRow.js +5 -2
  19. package/dist/components/icons.js +1 -2
  20. package/dist/index.d.ts +2 -0
  21. package/dist/index.js +1 -0
  22. package/dist/inquiriesStore.d.ts +134 -0
  23. package/dist/inquiriesStore.js +64 -0
  24. package/dist/patternAccess.d.ts +8 -2
  25. package/dist/patternAccess.js +17 -5
  26. package/dist/publishWire.d.ts +866 -0
  27. package/dist/publishWire.js +78 -0
  28. package/dist/requests.d.ts +361 -0
  29. package/dist/requests.js +180 -0
  30. package/dist/schema.d.ts +2 -0
  31. package/dist/schema.js +1 -0
  32. package/dist/server/authService.d.ts +1 -0
  33. package/dist/server/bookings.d.ts +2 -9
  34. package/dist/server/bookings.js +149 -31
  35. package/dist/server/createServer.js +4 -0
  36. package/dist/server/env.d.ts +3 -0
  37. package/dist/server/index.d.ts +1 -0
  38. package/dist/server/index.js +1 -0
  39. package/dist/server/inquiries.d.ts +9 -0
  40. package/dist/server/inquiries.js +150 -0
  41. package/dist/server/patternViewer.js +7 -1
  42. package/dist/server/requests.d.ts +76 -0
  43. package/dist/server/requests.js +328 -0
  44. package/dist/server/services.js +9 -1
  45. package/package.json +1 -1
@@ -102,8 +102,7 @@ const builtInIcons = {
102
102
  ],
103
103
  arrowDown: 'M12 5v14M6 13l6 6 6-6',
104
104
  logOut: [
105
- 'M14 4.5H7.5a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2H14',
106
- 'M19.5 12H10M16 8.5l3.5 3.5-3.5 3.5'
105
+ 'M20.25 12L9 12M20.25 12L15.75 16.5M20.25 12L15.75 7.5M11.25 20.25H5.75C4.64543 20.25 3.75 19.3546 3.75 18.25L3.75 5.75C3.75 4.64543 4.64543 3.75 5.75 3.75L11.25 3.75'
107
106
  ],
108
107
  today: 'M11.998 3.291V1.768M5.84 18.159L4.763 19.236M11.998 22.233V20.709M19.233 4.765L18.156 5.842M20.707 12H22.23M18.156 18.159L19.233 19.236M1.766 12H3.289M4.763 4.765L5.84 5.842M15.71 8.288C17.761 10.338 17.761 13.662 15.71 15.712C13.66 17.763 10.336 17.763 8.286 15.712C6.235 13.662 6.235 10.338 8.286 8.288C10.336 6.238 13.66 6.238 15.71 8.288Z',
109
108
  checklist: 'M11.75 16.25H20.25M11.75 7.75H20.25M3.75 8.625L5.417 9.75L8.75 5.25M3.75 17.625L5.417 18.75L8.75 14.25',
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export { defineApp } from './app.ts';
2
2
  export { Bookings, bookings } from './bookingsStore.ts';
3
3
  export type { BookingsWorld } from './bookingsMemory.ts';
4
+ export { Inquiries, inquiries } from './inquiriesStore.ts';
5
+ export type { InquiriesWorld } from './inquiriesStore.ts';
4
6
  export type { AppBlock } from './blocks.ts';
5
7
  export { ActionsStore, bindActions, rankActions } from './actions.ts';
6
8
  export type { Action, ActionsBuilder } from './actions.ts';
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export { defineApp } from "./app.js";
2
2
  export { Bookings, bookings } from "./bookingsStore.js";
3
+ export { Inquiries, inquiries } from "./inquiriesStore.js";
3
4
  export { ActionsStore, bindActions, rankActions } from "./actions.js";
4
5
  export { startApp } from "./start.js";
5
6
  export { appearance } from "./appearance.js";
@@ -0,0 +1,134 @@
1
+ import { z } from 'zod';
2
+ import type { WriteOutcome } from './access.ts';
3
+ import { inquiryValue } from './requests.ts';
4
+ import type { ServiceClient, ServiceMemory } from './services.ts';
5
+ type Fields = Readonly<Record<string, z.output<typeof inquiryValue>>>;
6
+ export type InquiriesWorld = {
7
+ sent?: {
8
+ source: string;
9
+ id: string;
10
+ fields: Fields;
11
+ }[];
12
+ sources?: string[];
13
+ };
14
+ declare const Inquiries_base: import("./store.ts").StoreClass<{
15
+ sent: z.ZodDefault<z.ZodNullable<z.ZodObject<{
16
+ source: z.ZodString;
17
+ id: z.ZodString;
18
+ }, z.core.$strip>>>;
19
+ isSending: z.ZodDefault<z.ZodBoolean>;
20
+ }, [], ServiceClient<{
21
+ readonly inquiries: {
22
+ readonly send: NoInfer<import("./services.ts").ServiceCall<"/requests/:source", {
23
+ fields: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>;
24
+ }, z.ZodObject<{
25
+ id: z.ZodString;
26
+ }, z.core.$strip>, false>>;
27
+ };
28
+ }>>;
29
+ export declare class Inquiries extends Inquiries_base {
30
+ send(source: string, fields: Fields): Promise<WriteOutcome>;
31
+ }
32
+ export declare const inquiries: {
33
+ readonly name: "inquiries";
34
+ readonly tables: {
35
+ requestStates: import("./table.ts").TableOf<"requestStates", {
36
+ readonly columns: {
37
+ readonly source: z.ZodString;
38
+ readonly requestId: z.ZodString;
39
+ readonly state: z.ZodEnum<{
40
+ done: "done";
41
+ open: "open";
42
+ }>;
43
+ readonly revision: z.ZodNumber;
44
+ readonly sequence: z.ZodNumber;
45
+ readonly updatedAt: z.ZodString;
46
+ };
47
+ readonly access: {
48
+ readonly read: "server";
49
+ readonly create: "server";
50
+ readonly update: "server";
51
+ readonly delete: "server";
52
+ };
53
+ readonly writes: "confirmed";
54
+ }>;
55
+ requestEvents: import("./table.ts").TableOf<"requestEvents", {
56
+ readonly columns: {
57
+ readonly source: z.ZodString;
58
+ readonly requestId: z.ZodString;
59
+ readonly kind: z.ZodEnum<{
60
+ done: "done";
61
+ accepted: "accepted";
62
+ declined: "declined";
63
+ replied: "replied";
64
+ received: "received";
65
+ }>;
66
+ };
67
+ readonly access: {
68
+ readonly read: "server";
69
+ readonly create: "server";
70
+ readonly update: "server";
71
+ readonly delete: "server";
72
+ };
73
+ readonly writes: "confirmed";
74
+ }>;
75
+ requestOutbox: import("./table.ts").TableOf<"requestOutbox", {
76
+ readonly columns: {
77
+ readonly source: z.ZodString;
78
+ readonly requestId: z.ZodString;
79
+ readonly subject: z.ZodString;
80
+ readonly text: z.ZodString;
81
+ readonly replyTo: z.ZodString;
82
+ readonly status: z.ZodEnum<{
83
+ failed: "failed";
84
+ pending: "pending";
85
+ sent: "sent";
86
+ sending: "sending";
87
+ }>;
88
+ readonly attempts: z.ZodNumber;
89
+ readonly nextAt: z.ZodNullable<z.ZodString>;
90
+ readonly sentAt: z.ZodNullable<z.ZodString>;
91
+ readonly claimedAt: z.ZodNullable<z.ZodString>;
92
+ };
93
+ readonly access: {
94
+ readonly read: "server";
95
+ readonly create: "server";
96
+ readonly update: "server";
97
+ readonly delete: "server";
98
+ };
99
+ readonly writes: "confirmed";
100
+ }>;
101
+ requestOperations: import("./table.ts").TableOf<"requestOperations", {
102
+ readonly columns: {
103
+ readonly result: z.ZodString;
104
+ };
105
+ readonly access: {
106
+ readonly read: "server";
107
+ readonly create: "server";
108
+ readonly update: "server";
109
+ readonly delete: "server";
110
+ };
111
+ readonly writes: "confirmed";
112
+ }>;
113
+ };
114
+ readonly services: {
115
+ readonly inquiries: {
116
+ readonly send: NoInfer<import("./services.ts").ServiceCall<"/requests/:source", {
117
+ fields: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>;
118
+ }, z.ZodObject<{
119
+ id: z.ZodString;
120
+ }, z.core.$strip>, false>>;
121
+ };
122
+ };
123
+ readonly memory: ServiceMemory<{
124
+ readonly inquiries: {
125
+ readonly send: NoInfer<import("./services.ts").ServiceCall<"/requests/:source", {
126
+ fields: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>;
127
+ }, z.ZodObject<{
128
+ id: z.ZodString;
129
+ }, z.core.$strip>, false>>;
130
+ };
131
+ }, unknown>;
132
+ readonly Store: typeof Inquiries;
133
+ };
134
+ export {};
@@ -0,0 +1,64 @@
1
+ import { z } from 'zod';
2
+ import { inquiryServices, inquiryValue, requestTables } from "./requests.js";
3
+ import { ServiceRefused, refused } from "./services.js";
4
+ import { defineStore } from "./store.js";
5
+ const Store = defineStore();
6
+ function worldOf(world) {
7
+ const found = Reflect.get(Object(world), 'inquiries');
8
+ return typeof found === 'object' && found !== null ? found : {};
9
+ }
10
+ const inquiryMemory = {
11
+ inquiries: {
12
+ send: (world, { source, fields }) => {
13
+ const current = worldOf(world);
14
+ if (current.sources !== undefined && !current.sources.includes(source)) {
15
+ throw refused(404, 'No such form');
16
+ }
17
+ const sent = current.sent ?? [];
18
+ const id = `${source}-${sent.length + 1}`;
19
+ Reflect.set(Object(world), 'inquiries', {
20
+ ...current,
21
+ sent: [...sent, { source, id, fields }]
22
+ });
23
+ return { id };
24
+ }
25
+ }
26
+ };
27
+ function outcomeOf(error) {
28
+ if (!(error instanceof ServiceRefused))
29
+ return 'failed';
30
+ if (error.status === 400 || error.status === 404)
31
+ return 'forbidden';
32
+ return error.status === 409 ? 'conflict' : 'failed';
33
+ }
34
+ export class Inquiries extends Store({
35
+ state: {
36
+ sent: z
37
+ .object({ source: z.string(), id: z.string() })
38
+ .nullable()
39
+ .default(null),
40
+ isSending: z.boolean().default(false)
41
+ }
42
+ }) {
43
+ async send(source, fields) {
44
+ this.set({ isSending: true });
45
+ try {
46
+ const { id } = await this.services.inquiries.send({ source, fields });
47
+ this.set({ sent: { source, id } });
48
+ return 'saved';
49
+ }
50
+ catch (error) {
51
+ return outcomeOf(error);
52
+ }
53
+ finally {
54
+ this.set({ isSending: false });
55
+ }
56
+ }
57
+ }
58
+ export const inquiries = {
59
+ name: 'inquiries',
60
+ tables: requestTables,
61
+ services: inquiryServices,
62
+ memory: inquiryMemory,
63
+ Store: Inquiries
64
+ };
@@ -2,6 +2,8 @@ import { z } from 'zod';
2
2
  export declare const TABLES_READ = "tables:read";
3
3
  export declare const MEDIA_WRITE = "media:write";
4
4
  export declare const TABLES_WRITE = "tables:write";
5
+ export declare const REQUESTS_READ = "requests:read";
6
+ export declare const REQUESTS_ACT = "requests:act";
5
7
  export declare const ASSERTION_SECONDS = 60;
6
8
  export declare const NEXT_PAGE_HEADER = "x-pattern-next";
7
9
  export declare const assertionKey: z.ZodObject<{
@@ -16,17 +18,21 @@ declare const assertionScope: z.ZodEnum<{
16
18
  "tables:read": "tables:read";
17
19
  "media:write": "media:write";
18
20
  "tables:write": "tables:write";
21
+ "requests:read": "requests:read";
22
+ "requests:act": "requests:act";
19
23
  }>;
20
24
  export type AssertionScope = z.output<typeof assertionScope>;
21
- export declare function signAssertion(key: AssertionKey, { sub, aud, scope }: {
25
+ export declare function signAssertion(key: AssertionKey, { sub, aud, scope, bound }: {
22
26
  sub: string;
23
27
  aud: string;
24
28
  scope: AssertionScope;
29
+ bound?: string;
25
30
  }, now: number): Promise<string>;
26
- export declare function verifiedAssertion(token: string, { hostname, keys, now, scope }: {
31
+ export declare function verifiedAssertion(token: string, { hostname, keys, now, scope, bound }: {
27
32
  hostname: string;
28
33
  keys: Readonly<Record<string, string>>;
29
34
  now: number;
30
35
  scope: AssertionScope;
36
+ bound?: string;
31
37
  }): Promise<string | undefined>;
32
38
  export {};
@@ -2,6 +2,8 @@ import { z } from 'zod';
2
2
  export const TABLES_READ = 'tables:read';
3
3
  export const MEDIA_WRITE = 'media:write';
4
4
  export const TABLES_WRITE = 'tables:write';
5
+ export const REQUESTS_READ = 'requests:read';
6
+ export const REQUESTS_ACT = 'requests:act';
5
7
  export const ASSERTION_SECONDS = 60;
6
8
  export const NEXT_PAGE_HEADER = 'x-pattern-next';
7
9
  const CLOCK_SKEW_SECONDS = 30;
@@ -13,7 +15,13 @@ export const assertionKey = z.object({
13
15
  x: z.string(),
14
16
  d: z.string()
15
17
  });
16
- const assertionScope = z.enum([TABLES_READ, TABLES_WRITE, MEDIA_WRITE]);
18
+ const assertionScope = z.enum([
19
+ TABLES_READ,
20
+ TABLES_WRITE,
21
+ MEDIA_WRITE,
22
+ REQUESTS_READ,
23
+ REQUESTS_ACT
24
+ ]);
17
25
  const assertionHeader = z.object({
18
26
  alg: z.literal('EdDSA'),
19
27
  typ: z.literal('JWT'),
@@ -24,7 +32,8 @@ const assertionClaims = z.object({
24
32
  aud: z.string(),
25
33
  scope: assertionScope,
26
34
  iat: z.int(),
27
- exp: z.int()
35
+ exp: z.int(),
36
+ bnd: z.string().optional()
28
37
  });
29
38
  const encoder = new TextEncoder();
30
39
  function base64url(bytes) {
@@ -56,14 +65,15 @@ function jsonOf(text) {
56
65
  function encoded(value) {
57
66
  return base64url(encoder.encode(JSON.stringify(value)));
58
67
  }
59
- export async function signAssertion(key, { sub, aud, scope }, now) {
68
+ export async function signAssertion(key, { sub, aud, scope, bound }, now) {
60
69
  const privateKey = await crypto.subtle.importKey('jwk', { kty: key.kty, crv: key.crv, x: key.x, d: key.d }, ED25519, false, ['sign']);
61
70
  const signed = `${encoded({ alg: 'EdDSA', typ: 'JWT', kid: key.kid })}.${encoded({
62
71
  sub,
63
72
  aud,
64
73
  scope,
65
74
  iat: now,
66
- exp: now + ASSERTION_SECONDS
75
+ exp: now + ASSERTION_SECONDS,
76
+ ...(bound === undefined ? {} : { bnd: bound })
67
77
  })}`;
68
78
  const signature = await crypto.subtle.sign(ED25519, privateKey, encoder.encode(signed));
69
79
  return `${signed}.${base64url(new Uint8Array(signature))}`;
@@ -83,7 +93,7 @@ async function isSignedBy(publicKey, signed, signature) {
83
93
  return false;
84
94
  }
85
95
  }
86
- export async function verifiedAssertion(token, { hostname, keys, now, scope }) {
96
+ export async function verifiedAssertion(token, { hostname, keys, now, scope, bound }) {
87
97
  const [header, claims, signature, ...rest] = token.split('.');
88
98
  if (header === undefined ||
89
99
  claims === undefined ||
@@ -107,6 +117,8 @@ export async function verifiedAssertion(token, { hostname, keys, now, scope }) {
107
117
  const { sub, aud, iat, exp } = parsed.data;
108
118
  if (parsed.data.scope !== scope)
109
119
  return undefined;
120
+ if (bound !== undefined && parsed.data.bnd !== bound)
121
+ return undefined;
110
122
  const isFresh = exp > iat &&
111
123
  exp - iat <= ASSERTION_SECONDS &&
112
124
  iat <= now + CLOCK_SKEW_SECONDS &&