@contractspec/lib.runtime-sandbox 0.11.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/_virtual/rolldown_runtime.js +18 -0
- package/dist/adapters/pglite/adapter.js +97 -0
- package/dist/adapters/pglite/adapter.js.map +1 -0
- package/dist/adapters/pglite/index.js +3 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/ports/database.port.d.ts +70 -0
- package/dist/ports/database.port.d.ts.map +1 -0
- package/dist/types/database.types.d.ts +47 -0
- package/dist/types/database.types.d.ts.map +1 -0
- package/dist/web/database/migrations.d.ts +12 -0
- package/dist/web/database/migrations.d.ts.map +1 -0
- package/dist/web/database/migrations.js +746 -0
- package/dist/web/database/migrations.js.map +1 -0
- package/dist/web/database/schema.d.ts +7349 -0
- package/dist/web/database/schema.d.ts.map +1 -0
- package/dist/web/database/schema.js +528 -0
- package/dist/web/database/schema.js.map +1 -0
- package/dist/web/events/local-pubsub.d.ts +10 -0
- package/dist/web/events/local-pubsub.d.ts.map +1 -0
- package/dist/web/events/local-pubsub.js +24 -0
- package/dist/web/events/local-pubsub.js.map +1 -0
- package/dist/web/graphql/local-client.d.ts +20 -0
- package/dist/web/graphql/local-client.d.ts.map +1 -0
- package/dist/web/graphql/local-client.js +536 -0
- package/dist/web/graphql/local-client.js.map +1 -0
- package/dist/web/index.d.ts +15 -0
- package/dist/web/index.d.ts.map +1 -0
- package/dist/web/index.js +68 -0
- package/dist/web/index.js.map +1 -0
- package/dist/web/runtime/seeders/index.js +358 -0
- package/dist/web/runtime/seeders/index.js.map +1 -0
- package/dist/web/runtime/services.d.ts +60 -0
- package/dist/web/runtime/services.d.ts.map +1 -0
- package/dist/web/runtime/services.js +80 -0
- package/dist/web/runtime/services.js.map +1 -0
- package/dist/web/storage/indexeddb.d.ts +22 -0
- package/dist/web/storage/indexeddb.d.ts.map +1 -0
- package/dist/web/storage/indexeddb.js +85 -0
- package/dist/web/storage/indexeddb.js.map +1 -0
- package/dist/web/utils/id.d.ts +5 -0
- package/dist/web/utils/id.d.ts.map +1 -0
- package/dist/web/utils/id.js +9 -0
- package/dist/web/utils/id.js.map +1 -0
- package/package.json +70 -0
- package/src/adapters/pglite/adapter.ts +152 -0
- package/src/adapters/pglite/index.ts +1 -0
- package/src/index.ts +41 -0
- package/src/ports/database.port.ts +82 -0
- package/src/ports/index.ts +4 -0
- package/src/types/database.types.ts +55 -0
- package/src/types/index.ts +1 -0
- package/src/web/database/migrations.ts +760 -0
- package/src/web/database/schema.ts +596 -0
- package/src/web/events/local-pubsub.ts +28 -0
- package/src/web/graphql/local-client.ts +747 -0
- package/src/web/index.ts +21 -0
- package/src/web/runtime/seeders/index.ts +449 -0
- package/src/web/runtime/services.ts +132 -0
- package/src/web/storage/indexeddb.ts +116 -0
- package/src/web/utils/id.ts +7 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-pubsub.d.ts","names":[],"sources":["../../../src/web/events/local-pubsub.ts"],"sourcesContent":[],"mappings":";KAAK,+BAA+B;AAA/B,cAEQ,aAAA,CAFuB;EAEvB,QAAA,SAAa;EAGyB,IAAA,CAAA,WAAA,OAAA,CAAA,CAAA,KAAA,EAAA,MAAA,EAAA,OAAA,EAAA,QAAA,CAAA,EAAA,IAAA;EAU5B,SAAA,CAAA,WAAA,OAAA,CAAA,CAAA,KAAA,EAAA,MAAA,EAAA,QAAA,EAAT,QAAS,CAAA,QAAA,CAAA,CAAA,EAAA,GAAA,GAAA,IAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/web/events/local-pubsub.ts
|
|
2
|
+
var LocalEventBus = class {
|
|
3
|
+
listeners = /* @__PURE__ */ new Map();
|
|
4
|
+
emit(event, payload) {
|
|
5
|
+
const listeners = this.listeners.get(event);
|
|
6
|
+
if (!listeners) return;
|
|
7
|
+
for (const listener of listeners) listener(payload);
|
|
8
|
+
}
|
|
9
|
+
subscribe(event, listener) {
|
|
10
|
+
let listeners = this.listeners.get(event);
|
|
11
|
+
if (!listeners) {
|
|
12
|
+
listeners = /* @__PURE__ */ new Set();
|
|
13
|
+
this.listeners.set(event, listeners);
|
|
14
|
+
}
|
|
15
|
+
listeners.add(listener);
|
|
16
|
+
return () => {
|
|
17
|
+
listeners.delete(listener);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { LocalEventBus };
|
|
24
|
+
//# sourceMappingURL=local-pubsub.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-pubsub.js","names":[],"sources":["../../../src/web/events/local-pubsub.ts"],"sourcesContent":["type Listener<TPayload> = (payload: TPayload) => void;\n\nexport class LocalEventBus {\n private listeners = new Map<string, Set<Listener<unknown>>>();\n\n emit<TPayload = unknown>(event: string, payload: TPayload): void {\n const listeners = this.listeners.get(event);\n if (!listeners) return;\n for (const listener of listeners) {\n listener(payload);\n }\n }\n\n subscribe<TPayload = unknown>(\n event: string,\n listener: Listener<TPayload>\n ): () => void {\n let listeners = this.listeners.get(event);\n if (!listeners) {\n listeners = new Set();\n this.listeners.set(event, listeners);\n }\n listeners.add(listener as Listener<unknown>);\n return () => {\n listeners.delete(listener as Listener<unknown>);\n };\n }\n}\n"],"mappings":";AAEA,IAAa,gBAAb,MAA2B;CACzB,AAAQ,4BAAY,IAAI,KAAqC;CAE7D,KAAyB,OAAe,SAAyB;EAC/D,MAAM,YAAY,KAAK,UAAU,IAAI,MAAM;AAC3C,MAAI,CAAC,UAAW;AAChB,OAAK,MAAM,YAAY,UACrB,UAAS,QAAQ;;CAIrB,UACE,OACA,UACY;EACZ,IAAI,YAAY,KAAK,UAAU,IAAI,MAAM;AACzC,MAAI,CAAC,WAAW;AACd,+BAAY,IAAI,KAAK;AACrB,QAAK,UAAU,IAAI,OAAO,UAAU;;AAEtC,YAAU,IAAI,SAA8B;AAC5C,eAAa;AACX,aAAU,OAAO,SAA8B"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { LocalStorageService } from "../storage/indexeddb.js";
|
|
2
|
+
import { LocalEventBus } from "../events/local-pubsub.js";
|
|
3
|
+
import { ApolloClient } from "@apollo/client";
|
|
4
|
+
import { DatabasePort } from "@contractspec/lib.runtime-sandbox";
|
|
5
|
+
|
|
6
|
+
//#region src/web/graphql/local-client.d.ts
|
|
7
|
+
interface LocalGraphQLClientOptions {
|
|
8
|
+
db: DatabasePort;
|
|
9
|
+
storage: LocalStorageService;
|
|
10
|
+
pubsub?: LocalEventBus;
|
|
11
|
+
}
|
|
12
|
+
declare class LocalGraphQLClient {
|
|
13
|
+
private readonly options;
|
|
14
|
+
readonly apollo: InstanceType<typeof ApolloClient>;
|
|
15
|
+
constructor(options: LocalGraphQLClientOptions);
|
|
16
|
+
private createResolvers;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { LocalGraphQLClient, LocalGraphQLClientOptions };
|
|
20
|
+
//# sourceMappingURL=local-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-client.d.ts","names":[],"sources":["../../../src/web/graphql/local-client.ts"],"sourcesContent":[],"mappings":";;;;;;UA8NiB,yBAAA;MACX;EADW,OAAA,EAEN,mBAF+B;EACpC,MAAA,CAAA,EAEK,aAFL;;AAEK,cAGE,kBAAA,CAHF;EAAa,iBAAA,OAAA;EAGX,SAAA,MAAA,EACM,YADY,CAAA,OACQ,YADR,CAAA;EACQ,WAAA,CAAA,OAAA,EAEC,yBAFD;EAApB,QAAA,eAAA"}
|
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
import { generateId } from "../utils/id.js";
|
|
2
|
+
import { LocalEventBus } from "../events/local-pubsub.js";
|
|
3
|
+
import { ApolloClient, InMemoryCache } from "@apollo/client";
|
|
4
|
+
import { SchemaLink } from "@apollo/client/link/schema";
|
|
5
|
+
import { makeExecutableSchema } from "@graphql-tools/schema";
|
|
6
|
+
import { GraphQLScalarType, Kind } from "graphql";
|
|
7
|
+
|
|
8
|
+
//#region src/web/graphql/local-client.ts
|
|
9
|
+
const typeDefs = `
|
|
10
|
+
scalar DateTime
|
|
11
|
+
|
|
12
|
+
enum TaskPriority {
|
|
13
|
+
LOW
|
|
14
|
+
MEDIUM
|
|
15
|
+
HIGH
|
|
16
|
+
URGENT
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
enum MessageStatus {
|
|
20
|
+
SENT
|
|
21
|
+
DELIVERED
|
|
22
|
+
READ
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
enum RecipeLocale {
|
|
26
|
+
EN
|
|
27
|
+
FR
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type TaskCategory {
|
|
31
|
+
id: ID!
|
|
32
|
+
projectId: ID!
|
|
33
|
+
name: String!
|
|
34
|
+
color: String
|
|
35
|
+
createdAt: DateTime!
|
|
36
|
+
updatedAt: DateTime!
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type Task {
|
|
40
|
+
id: ID!
|
|
41
|
+
projectId: ID!
|
|
42
|
+
categoryId: ID
|
|
43
|
+
title: String!
|
|
44
|
+
description: String
|
|
45
|
+
completed: Boolean!
|
|
46
|
+
priority: TaskPriority!
|
|
47
|
+
dueDate: DateTime
|
|
48
|
+
tags: [String!]!
|
|
49
|
+
createdAt: DateTime!
|
|
50
|
+
updatedAt: DateTime!
|
|
51
|
+
category: TaskCategory
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
input CreateTaskInput {
|
|
55
|
+
projectId: ID!
|
|
56
|
+
categoryId: ID
|
|
57
|
+
title: String!
|
|
58
|
+
description: String
|
|
59
|
+
priority: TaskPriority = MEDIUM
|
|
60
|
+
dueDate: DateTime
|
|
61
|
+
tags: [String!]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
input UpdateTaskInput {
|
|
65
|
+
categoryId: ID
|
|
66
|
+
title: String
|
|
67
|
+
description: String
|
|
68
|
+
priority: TaskPriority
|
|
69
|
+
dueDate: DateTime
|
|
70
|
+
tags: [String!]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
type ConversationParticipant {
|
|
74
|
+
id: ID!
|
|
75
|
+
conversationId: ID!
|
|
76
|
+
projectId: ID!
|
|
77
|
+
userId: String!
|
|
78
|
+
displayName: String
|
|
79
|
+
role: String
|
|
80
|
+
joinedAt: DateTime!
|
|
81
|
+
lastReadAt: DateTime
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
input ConversationParticipantInput {
|
|
85
|
+
userId: String!
|
|
86
|
+
displayName: String
|
|
87
|
+
role: String
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
type Message {
|
|
91
|
+
id: ID!
|
|
92
|
+
conversationId: ID!
|
|
93
|
+
projectId: ID!
|
|
94
|
+
senderId: String!
|
|
95
|
+
senderName: String
|
|
96
|
+
content: String!
|
|
97
|
+
attachments: [String!]!
|
|
98
|
+
status: MessageStatus!
|
|
99
|
+
createdAt: DateTime!
|
|
100
|
+
updatedAt: DateTime!
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
input SendMessageInput {
|
|
104
|
+
conversationId: ID!
|
|
105
|
+
projectId: ID!
|
|
106
|
+
senderId: String!
|
|
107
|
+
senderName: String
|
|
108
|
+
content: String!
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
input CreateConversationInput {
|
|
112
|
+
projectId: ID!
|
|
113
|
+
name: String
|
|
114
|
+
isGroup: Boolean = false
|
|
115
|
+
avatarUrl: String
|
|
116
|
+
participants: [ConversationParticipantInput!]!
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
type Conversation {
|
|
120
|
+
id: ID!
|
|
121
|
+
projectId: ID!
|
|
122
|
+
name: String
|
|
123
|
+
isGroup: Boolean!
|
|
124
|
+
avatarUrl: String
|
|
125
|
+
lastMessageId: ID
|
|
126
|
+
updatedAt: DateTime!
|
|
127
|
+
participants: [ConversationParticipant!]!
|
|
128
|
+
messages(limit: Int = 50): [Message!]!
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
type RecipeCategory {
|
|
132
|
+
id: ID!
|
|
133
|
+
nameEn: String!
|
|
134
|
+
nameFr: String!
|
|
135
|
+
icon: String
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
type RecipeIngredient {
|
|
139
|
+
id: ID!
|
|
140
|
+
name: String!
|
|
141
|
+
quantity: String!
|
|
142
|
+
ordering: Int!
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
type RecipeInstruction {
|
|
146
|
+
id: ID!
|
|
147
|
+
content: String!
|
|
148
|
+
ordering: Int!
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
type Recipe {
|
|
152
|
+
id: ID!
|
|
153
|
+
projectId: ID!
|
|
154
|
+
slugEn: String!
|
|
155
|
+
slugFr: String!
|
|
156
|
+
name: String!
|
|
157
|
+
description: String
|
|
158
|
+
heroImageUrl: String
|
|
159
|
+
prepTimeMinutes: Int
|
|
160
|
+
cookTimeMinutes: Int
|
|
161
|
+
servings: Int
|
|
162
|
+
isFavorite: Boolean!
|
|
163
|
+
locale: RecipeLocale!
|
|
164
|
+
category: RecipeCategory
|
|
165
|
+
ingredients: [RecipeIngredient!]!
|
|
166
|
+
instructions: [RecipeInstruction!]!
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
type Query {
|
|
170
|
+
taskCategories(projectId: ID!): [TaskCategory!]!
|
|
171
|
+
tasks(projectId: ID!): [Task!]!
|
|
172
|
+
conversations(projectId: ID!): [Conversation!]!
|
|
173
|
+
messages(conversationId: ID!, limit: Int = 50): [Message!]!
|
|
174
|
+
recipes(projectId: ID!, locale: RecipeLocale = EN): [Recipe!]!
|
|
175
|
+
recipe(id: ID!, locale: RecipeLocale = EN): Recipe
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
type Mutation {
|
|
179
|
+
createTask(input: CreateTaskInput!): Task!
|
|
180
|
+
updateTask(id: ID!, input: UpdateTaskInput!): Task!
|
|
181
|
+
toggleTask(id: ID!, completed: Boolean!): Task!
|
|
182
|
+
deleteTask(id: ID!): Boolean!
|
|
183
|
+
createConversation(input: CreateConversationInput!): Conversation!
|
|
184
|
+
sendMessage(input: SendMessageInput!): Message!
|
|
185
|
+
setMessagesRead(conversationId: ID!, userId: String!): Boolean!
|
|
186
|
+
favoriteRecipe(id: ID!, isFavorite: Boolean!): Recipe!
|
|
187
|
+
}
|
|
188
|
+
`;
|
|
189
|
+
const DateTimeScalar = new GraphQLScalarType({
|
|
190
|
+
name: "DateTime",
|
|
191
|
+
parseValue(value) {
|
|
192
|
+
return value ? new Date(value).toISOString() : null;
|
|
193
|
+
},
|
|
194
|
+
serialize(value) {
|
|
195
|
+
if (!value) return null;
|
|
196
|
+
if (typeof value === "string") return value;
|
|
197
|
+
return new Date(value).toISOString();
|
|
198
|
+
},
|
|
199
|
+
parseLiteral(ast) {
|
|
200
|
+
if (ast.kind === Kind.STRING) return new Date(ast.value).toISOString();
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
var LocalGraphQLClient = class {
|
|
205
|
+
apollo;
|
|
206
|
+
constructor(options) {
|
|
207
|
+
this.options = options;
|
|
208
|
+
const schema = makeExecutableSchema({
|
|
209
|
+
typeDefs,
|
|
210
|
+
resolvers: this.createResolvers()
|
|
211
|
+
});
|
|
212
|
+
this.apollo = new ApolloClient({
|
|
213
|
+
cache: new InMemoryCache(),
|
|
214
|
+
link: new SchemaLink({
|
|
215
|
+
schema,
|
|
216
|
+
context: () => ({
|
|
217
|
+
db: this.options.db,
|
|
218
|
+
storage: this.options.storage,
|
|
219
|
+
pubsub: this.options.pubsub ?? new LocalEventBus()
|
|
220
|
+
})
|
|
221
|
+
}),
|
|
222
|
+
devtools: { enabled: typeof window !== "undefined" }
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
createResolvers() {
|
|
226
|
+
return {
|
|
227
|
+
DateTime: DateTimeScalar,
|
|
228
|
+
Query: {
|
|
229
|
+
taskCategories: async (_, args, ctx) => {
|
|
230
|
+
return (await ctx.db.query(`SELECT * FROM template_task_category WHERE "projectId" = $1 ORDER BY name ASC`, [args.projectId])).rows.map(mapTaskCategory);
|
|
231
|
+
},
|
|
232
|
+
tasks: async (_, args, ctx) => {
|
|
233
|
+
return (await ctx.db.query(`SELECT * FROM template_task WHERE "projectId" = $1 ORDER BY "createdAt" DESC`, [args.projectId])).rows.map(mapTask);
|
|
234
|
+
},
|
|
235
|
+
conversations: async (_, args, ctx) => {
|
|
236
|
+
return (await ctx.db.query(`SELECT * FROM template_conversation WHERE "projectId" = $1 ORDER BY "updatedAt" DESC`, [args.projectId])).rows.map(mapConversation);
|
|
237
|
+
},
|
|
238
|
+
messages: async (_, args, ctx) => {
|
|
239
|
+
return (await ctx.db.query(`SELECT * FROM template_message WHERE "conversationId" = $1 ORDER BY "createdAt" DESC LIMIT $2`, [args.conversationId, args.limit])).rows.map(mapMessage);
|
|
240
|
+
},
|
|
241
|
+
recipes: async (_, args, ctx) => {
|
|
242
|
+
return (await ctx.db.query(`SELECT * FROM template_recipe WHERE "projectId" = $1 ORDER BY "nameEn" ASC`, [args.projectId])).rows.map((row) => mapRecipe(row, args.locale));
|
|
243
|
+
},
|
|
244
|
+
recipe: async (_, args, ctx) => {
|
|
245
|
+
const result = await ctx.db.query(`SELECT * FROM template_recipe WHERE id = $1 LIMIT 1`, [args.id]);
|
|
246
|
+
if (!result.rows.length || !result.rows[0]) return null;
|
|
247
|
+
return mapRecipe(result.rows[0], args.locale);
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
Mutation: {
|
|
251
|
+
createTask: async (_, args, ctx) => {
|
|
252
|
+
const id = generateId("task");
|
|
253
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
254
|
+
const tags = JSON.stringify(args.input.tags ?? []);
|
|
255
|
+
await ctx.db.execute(`INSERT INTO template_task (id, "projectId", "categoryId", title, description, completed, priority, "dueDate", tags, "createdAt", "updatedAt")
|
|
256
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`, [
|
|
257
|
+
id,
|
|
258
|
+
args.input.projectId,
|
|
259
|
+
args.input.categoryId ?? null,
|
|
260
|
+
args.input.title,
|
|
261
|
+
args.input.description ?? null,
|
|
262
|
+
0,
|
|
263
|
+
args.input.priority ?? "MEDIUM",
|
|
264
|
+
args.input.dueDate ?? null,
|
|
265
|
+
tags,
|
|
266
|
+
now,
|
|
267
|
+
now
|
|
268
|
+
]);
|
|
269
|
+
const result = await ctx.db.query(`SELECT * FROM template_task WHERE id = $1 LIMIT 1`, [id]);
|
|
270
|
+
if (!result.rows.length || !result.rows[0]) throw new Error("Failed to create task");
|
|
271
|
+
return mapTask(result.rows[0]);
|
|
272
|
+
},
|
|
273
|
+
updateTask: async (_, args, ctx) => {
|
|
274
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
275
|
+
await ctx.db.execute(`UPDATE template_task
|
|
276
|
+
SET "categoryId" = COALESCE($1, "categoryId"),
|
|
277
|
+
title = COALESCE($2, title),
|
|
278
|
+
description = COALESCE($3, description),
|
|
279
|
+
priority = COALESCE($4, priority),
|
|
280
|
+
"dueDate" = COALESCE($5, "dueDate"),
|
|
281
|
+
tags = COALESCE($6, tags),
|
|
282
|
+
"updatedAt" = $7
|
|
283
|
+
WHERE id = $8`, [
|
|
284
|
+
args.input.categoryId ?? null,
|
|
285
|
+
args.input.title ?? null,
|
|
286
|
+
args.input.description ?? null,
|
|
287
|
+
args.input.priority ?? null,
|
|
288
|
+
args.input.dueDate ?? null,
|
|
289
|
+
args.input.tags ? JSON.stringify(args.input.tags) : null,
|
|
290
|
+
now,
|
|
291
|
+
args.id
|
|
292
|
+
]);
|
|
293
|
+
const result = await ctx.db.query(`SELECT * FROM template_task WHERE id = $1 LIMIT 1`, [args.id]);
|
|
294
|
+
if (!result.rows.length || !result.rows[0]) throw new Error("Task not found");
|
|
295
|
+
return mapTask(result.rows[0]);
|
|
296
|
+
},
|
|
297
|
+
toggleTask: async (_, args, ctx) => {
|
|
298
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
299
|
+
await ctx.db.execute(`UPDATE template_task SET completed = $1, "updatedAt" = $2 WHERE id = $3`, [
|
|
300
|
+
args.completed ? 1 : 0,
|
|
301
|
+
now,
|
|
302
|
+
args.id
|
|
303
|
+
]);
|
|
304
|
+
const result = await ctx.db.query(`SELECT * FROM template_task WHERE id = $1 LIMIT 1`, [args.id]);
|
|
305
|
+
if (!result.rows.length || !result.rows[0]) throw new Error("Task not found");
|
|
306
|
+
return mapTask(result.rows[0]);
|
|
307
|
+
},
|
|
308
|
+
deleteTask: async (_, args, ctx) => {
|
|
309
|
+
await ctx.db.execute(`DELETE FROM template_task WHERE id = $1`, [args.id]);
|
|
310
|
+
return true;
|
|
311
|
+
},
|
|
312
|
+
createConversation: async (_, args, ctx) => {
|
|
313
|
+
const id = generateId("conversation");
|
|
314
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
315
|
+
await ctx.db.execute(`INSERT INTO template_conversation (id, "projectId", name, "isGroup", "avatarUrl", "updatedAt")
|
|
316
|
+
VALUES ($1, $2, $3, $4, $5, $6)`, [
|
|
317
|
+
id,
|
|
318
|
+
args.input.projectId,
|
|
319
|
+
args.input.name ?? null,
|
|
320
|
+
args.input.isGroup ? 1 : 0,
|
|
321
|
+
args.input.avatarUrl ?? null,
|
|
322
|
+
now
|
|
323
|
+
]);
|
|
324
|
+
const participants = args.input.participants ?? [];
|
|
325
|
+
for (const participant of participants) await ctx.db.execute(`INSERT INTO template_conversation_participant (id, "conversationId", "projectId", "userId", "displayName", role, "joinedAt")
|
|
326
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)`, [
|
|
327
|
+
generateId("participant"),
|
|
328
|
+
id,
|
|
329
|
+
args.input.projectId,
|
|
330
|
+
participant.userId,
|
|
331
|
+
participant.displayName ?? null,
|
|
332
|
+
participant.role ?? null,
|
|
333
|
+
now
|
|
334
|
+
]);
|
|
335
|
+
const result = await ctx.db.query(`SELECT * FROM template_conversation WHERE id = $1 LIMIT 1`, [id]);
|
|
336
|
+
if (!result.rows.length || !result.rows[0]) throw new Error("Failed to create conversation");
|
|
337
|
+
return mapConversation(result.rows[0]);
|
|
338
|
+
},
|
|
339
|
+
sendMessage: async (_, args, ctx) => {
|
|
340
|
+
const id = generateId("message");
|
|
341
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
342
|
+
await ctx.db.execute(`INSERT INTO template_message (id, "conversationId", "projectId", "senderId", "senderName", content, attachments, status, "createdAt", "updatedAt")
|
|
343
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`, [
|
|
344
|
+
id,
|
|
345
|
+
args.input.conversationId,
|
|
346
|
+
args.input.projectId,
|
|
347
|
+
args.input.senderId,
|
|
348
|
+
args.input.senderName ?? null,
|
|
349
|
+
args.input.content,
|
|
350
|
+
JSON.stringify([]),
|
|
351
|
+
"SENT",
|
|
352
|
+
now,
|
|
353
|
+
now
|
|
354
|
+
]);
|
|
355
|
+
await ctx.db.execute(`UPDATE template_conversation SET "lastMessageId" = $1, "updatedAt" = $2 WHERE id = $3`, [
|
|
356
|
+
id,
|
|
357
|
+
now,
|
|
358
|
+
args.input.conversationId
|
|
359
|
+
]);
|
|
360
|
+
const result = await ctx.db.query(`SELECT * FROM template_message WHERE id = $1`, [id]);
|
|
361
|
+
if (!result.rows.length || !result.rows[0]) throw new Error("Failed to send message");
|
|
362
|
+
const message = mapMessage(result.rows[0]);
|
|
363
|
+
ctx.pubsub.emit("message:new", message);
|
|
364
|
+
return message;
|
|
365
|
+
},
|
|
366
|
+
setMessagesRead: async (_, args, ctx) => {
|
|
367
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
368
|
+
await ctx.db.execute(`UPDATE template_conversation_participant
|
|
369
|
+
SET "lastReadAt" = $1
|
|
370
|
+
WHERE "conversationId" = $2 AND "userId" = $3`, [
|
|
371
|
+
now,
|
|
372
|
+
args.conversationId,
|
|
373
|
+
args.userId
|
|
374
|
+
]);
|
|
375
|
+
return true;
|
|
376
|
+
},
|
|
377
|
+
favoriteRecipe: async (_, args, ctx) => {
|
|
378
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
379
|
+
await ctx.db.execute(`UPDATE template_recipe SET "isFavorite" = $1, "updatedAt" = $2 WHERE id = $3`, [
|
|
380
|
+
args.isFavorite ? 1 : 0,
|
|
381
|
+
now,
|
|
382
|
+
args.id
|
|
383
|
+
]);
|
|
384
|
+
const result = await ctx.db.query(`SELECT * FROM template_recipe WHERE id = $1 LIMIT 1`, [args.id]);
|
|
385
|
+
if (!result.rows.length || !result.rows[0]) throw new Error("Recipe not found");
|
|
386
|
+
return mapRecipe(result.rows[0], "EN");
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
Task: { category: async (parent, _, ctx) => {
|
|
390
|
+
if (!parent.categoryId) return null;
|
|
391
|
+
const result = await ctx.db.query(`SELECT * FROM template_task_category WHERE id = $1 LIMIT 1`, [parent.categoryId]);
|
|
392
|
+
if (!result.rows.length || !result.rows[0]) return null;
|
|
393
|
+
return mapTaskCategory(result.rows[0]);
|
|
394
|
+
} },
|
|
395
|
+
Conversation: {
|
|
396
|
+
participants: async (parent, _, ctx) => {
|
|
397
|
+
return (await ctx.db.query(`SELECT * FROM template_conversation_participant WHERE "conversationId" = $1 ORDER BY "joinedAt" ASC`, [parent.id])).rows.map(mapParticipant);
|
|
398
|
+
},
|
|
399
|
+
messages: async (parent, args, ctx) => {
|
|
400
|
+
return (await ctx.db.query(`SELECT * FROM template_message WHERE "conversationId" = $1 ORDER BY "createdAt" DESC LIMIT $2`, [parent.id, args.limit])).rows.map(mapMessage);
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
Recipe: {
|
|
404
|
+
category: async (parent, _, ctx) => {
|
|
405
|
+
if (!parent.categoryId) return null;
|
|
406
|
+
const result = await ctx.db.query(`SELECT * FROM template_recipe_category WHERE id = $1 LIMIT 1`, [parent.categoryId]);
|
|
407
|
+
if (!result.rows.length || !result.rows[0]) return null;
|
|
408
|
+
return mapRecipeCategory(result.rows[0]);
|
|
409
|
+
},
|
|
410
|
+
ingredients: async (parent, _, ctx) => {
|
|
411
|
+
return (await ctx.db.query(`SELECT * FROM template_recipe_ingredient WHERE "recipeId" = $1 ORDER BY ordering ASC`, [parent.id])).rows.map((row) => mapRecipeIngredient(row, parent.locale));
|
|
412
|
+
},
|
|
413
|
+
instructions: async (parent, _, ctx) => {
|
|
414
|
+
return (await ctx.db.query(`SELECT * FROM template_recipe_instruction WHERE "recipeId" = $1 ORDER BY ordering ASC`, [parent.id])).rows.map((row) => mapRecipeInstruction(row, parent.locale));
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
function mapTaskCategory(row) {
|
|
421
|
+
return {
|
|
422
|
+
id: row.id,
|
|
423
|
+
projectId: row.projectId,
|
|
424
|
+
name: row.name,
|
|
425
|
+
color: row.color,
|
|
426
|
+
createdAt: row.createdAt,
|
|
427
|
+
updatedAt: row.updatedAt
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
function mapTask(row) {
|
|
431
|
+
return {
|
|
432
|
+
id: row.id,
|
|
433
|
+
projectId: row.projectId,
|
|
434
|
+
categoryId: row.categoryId,
|
|
435
|
+
title: row.title,
|
|
436
|
+
description: row.description,
|
|
437
|
+
completed: Boolean(row.completed),
|
|
438
|
+
priority: row.priority ?? "MEDIUM",
|
|
439
|
+
dueDate: row.dueDate,
|
|
440
|
+
tags: parseTags(row.tags),
|
|
441
|
+
createdAt: row.createdAt,
|
|
442
|
+
updatedAt: row.updatedAt
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
function parseTags(value) {
|
|
446
|
+
if (typeof value !== "string") return [];
|
|
447
|
+
try {
|
|
448
|
+
const parsed = JSON.parse(value);
|
|
449
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
450
|
+
} catch {
|
|
451
|
+
return [];
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
function mapConversation(row) {
|
|
455
|
+
return {
|
|
456
|
+
id: row.id,
|
|
457
|
+
projectId: row.projectId,
|
|
458
|
+
name: row.name,
|
|
459
|
+
isGroup: Boolean(row.isGroup),
|
|
460
|
+
avatarUrl: row.avatarUrl,
|
|
461
|
+
lastMessageId: row.lastMessageId,
|
|
462
|
+
updatedAt: row.updatedAt
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
function mapParticipant(row) {
|
|
466
|
+
return {
|
|
467
|
+
id: row.id,
|
|
468
|
+
conversationId: row.conversationId,
|
|
469
|
+
projectId: row.projectId,
|
|
470
|
+
userId: row.userId,
|
|
471
|
+
displayName: row.displayName,
|
|
472
|
+
role: row.role,
|
|
473
|
+
joinedAt: row.joinedAt,
|
|
474
|
+
lastReadAt: row.lastReadAt
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
function mapMessage(row) {
|
|
478
|
+
return {
|
|
479
|
+
id: row.id,
|
|
480
|
+
conversationId: row.conversationId,
|
|
481
|
+
projectId: row.projectId,
|
|
482
|
+
senderId: row.senderId,
|
|
483
|
+
senderName: row.senderName,
|
|
484
|
+
content: row.content,
|
|
485
|
+
attachments: [],
|
|
486
|
+
status: row.status ?? "SENT",
|
|
487
|
+
createdAt: row.createdAt,
|
|
488
|
+
updatedAt: row.updatedAt
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
function mapRecipe(row, locale) {
|
|
492
|
+
return {
|
|
493
|
+
id: row.id,
|
|
494
|
+
projectId: row.projectId,
|
|
495
|
+
slugEn: row.slugEn,
|
|
496
|
+
slugFr: row.slugFr,
|
|
497
|
+
name: locale === "FR" ? row.nameFr : row.nameEn,
|
|
498
|
+
description: locale === "FR" ? row.descriptionFr : row.descriptionEn,
|
|
499
|
+
heroImageUrl: row.heroImageUrl,
|
|
500
|
+
prepTimeMinutes: row.prepTimeMinutes ?? null,
|
|
501
|
+
cookTimeMinutes: row.cookTimeMinutes ?? null,
|
|
502
|
+
servings: row.servings ?? null,
|
|
503
|
+
isFavorite: Boolean(row.isFavorite),
|
|
504
|
+
locale,
|
|
505
|
+
categoryId: row.categoryId,
|
|
506
|
+
createdAt: row.createdAt,
|
|
507
|
+
updatedAt: row.updatedAt
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
function mapRecipeCategory(row) {
|
|
511
|
+
return {
|
|
512
|
+
id: row.id,
|
|
513
|
+
nameEn: row.nameEn,
|
|
514
|
+
nameFr: row.nameFr,
|
|
515
|
+
icon: row.icon
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
function mapRecipeIngredient(row, locale) {
|
|
519
|
+
return {
|
|
520
|
+
id: row.id,
|
|
521
|
+
name: locale === "FR" ? row.nameFr : row.nameEn,
|
|
522
|
+
quantity: row.quantity,
|
|
523
|
+
ordering: row.ordering ?? 0
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
function mapRecipeInstruction(row, locale) {
|
|
527
|
+
return {
|
|
528
|
+
id: row.id,
|
|
529
|
+
content: locale === "FR" ? row.contentFr : row.contentEn,
|
|
530
|
+
ordering: row.ordering ?? 0
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
//#endregion
|
|
535
|
+
export { LocalGraphQLClient };
|
|
536
|
+
//# sourceMappingURL=local-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-client.js","names":[],"sources":["../../../src/web/graphql/local-client.ts"],"sourcesContent":["import { ApolloClient, InMemoryCache } from '@apollo/client';\nimport { SchemaLink } from '@apollo/client/link/schema';\nimport { makeExecutableSchema } from '@graphql-tools/schema';\nimport { GraphQLScalarType, Kind } from 'graphql';\n\nimport type { DatabasePort, DbRow } from '@contractspec/lib.runtime-sandbox';\nimport { LocalEventBus } from '../events/local-pubsub';\nimport { LocalStorageService } from '../storage/indexeddb';\nimport { generateId } from '../utils/id';\n\nconst typeDefs = /* GraphQL */ `\n scalar DateTime\n\n enum TaskPriority {\n LOW\n MEDIUM\n HIGH\n URGENT\n }\n\n enum MessageStatus {\n SENT\n DELIVERED\n READ\n }\n\n enum RecipeLocale {\n EN\n FR\n }\n\n type TaskCategory {\n id: ID!\n projectId: ID!\n name: String!\n color: String\n createdAt: DateTime!\n updatedAt: DateTime!\n }\n\n type Task {\n id: ID!\n projectId: ID!\n categoryId: ID\n title: String!\n description: String\n completed: Boolean!\n priority: TaskPriority!\n dueDate: DateTime\n tags: [String!]!\n createdAt: DateTime!\n updatedAt: DateTime!\n category: TaskCategory\n }\n\n input CreateTaskInput {\n projectId: ID!\n categoryId: ID\n title: String!\n description: String\n priority: TaskPriority = MEDIUM\n dueDate: DateTime\n tags: [String!]\n }\n\n input UpdateTaskInput {\n categoryId: ID\n title: String\n description: String\n priority: TaskPriority\n dueDate: DateTime\n tags: [String!]\n }\n\n type ConversationParticipant {\n id: ID!\n conversationId: ID!\n projectId: ID!\n userId: String!\n displayName: String\n role: String\n joinedAt: DateTime!\n lastReadAt: DateTime\n }\n\n input ConversationParticipantInput {\n userId: String!\n displayName: String\n role: String\n }\n\n type Message {\n id: ID!\n conversationId: ID!\n projectId: ID!\n senderId: String!\n senderName: String\n content: String!\n attachments: [String!]!\n status: MessageStatus!\n createdAt: DateTime!\n updatedAt: DateTime!\n }\n\n input SendMessageInput {\n conversationId: ID!\n projectId: ID!\n senderId: String!\n senderName: String\n content: String!\n }\n\n input CreateConversationInput {\n projectId: ID!\n name: String\n isGroup: Boolean = false\n avatarUrl: String\n participants: [ConversationParticipantInput!]!\n }\n\n type Conversation {\n id: ID!\n projectId: ID!\n name: String\n isGroup: Boolean!\n avatarUrl: String\n lastMessageId: ID\n updatedAt: DateTime!\n participants: [ConversationParticipant!]!\n messages(limit: Int = 50): [Message!]!\n }\n\n type RecipeCategory {\n id: ID!\n nameEn: String!\n nameFr: String!\n icon: String\n }\n\n type RecipeIngredient {\n id: ID!\n name: String!\n quantity: String!\n ordering: Int!\n }\n\n type RecipeInstruction {\n id: ID!\n content: String!\n ordering: Int!\n }\n\n type Recipe {\n id: ID!\n projectId: ID!\n slugEn: String!\n slugFr: String!\n name: String!\n description: String\n heroImageUrl: String\n prepTimeMinutes: Int\n cookTimeMinutes: Int\n servings: Int\n isFavorite: Boolean!\n locale: RecipeLocale!\n category: RecipeCategory\n ingredients: [RecipeIngredient!]!\n instructions: [RecipeInstruction!]!\n }\n\n type Query {\n taskCategories(projectId: ID!): [TaskCategory!]!\n tasks(projectId: ID!): [Task!]!\n conversations(projectId: ID!): [Conversation!]!\n messages(conversationId: ID!, limit: Int = 50): [Message!]!\n recipes(projectId: ID!, locale: RecipeLocale = EN): [Recipe!]!\n recipe(id: ID!, locale: RecipeLocale = EN): Recipe\n }\n\n type Mutation {\n createTask(input: CreateTaskInput!): Task!\n updateTask(id: ID!, input: UpdateTaskInput!): Task!\n toggleTask(id: ID!, completed: Boolean!): Task!\n deleteTask(id: ID!): Boolean!\n createConversation(input: CreateConversationInput!): Conversation!\n sendMessage(input: SendMessageInput!): Message!\n setMessagesRead(conversationId: ID!, userId: String!): Boolean!\n favoriteRecipe(id: ID!, isFavorite: Boolean!): Recipe!\n }\n`;\n\ninterface ResolverContext {\n db: DatabasePort;\n storage: LocalStorageService;\n pubsub: LocalEventBus;\n}\n\ntype ResolverParent = Record<string, unknown>;\n\n/**\n * Local row type for query results\n */\ntype LocalRow = DbRow;\n\nconst DateTimeScalar = new GraphQLScalarType({\n name: 'DateTime',\n parseValue(value: unknown) {\n return value ? new Date(value as string).toISOString() : null;\n },\n serialize(value: unknown) {\n if (!value) return null;\n if (typeof value === 'string') return value;\n return new Date(value as string).toISOString();\n },\n parseLiteral(ast) {\n if (ast.kind === Kind.STRING) {\n return new Date(ast.value).toISOString();\n }\n return null;\n },\n});\n\nexport interface LocalGraphQLClientOptions {\n db: DatabasePort;\n storage: LocalStorageService;\n pubsub?: LocalEventBus;\n}\n\nexport class LocalGraphQLClient {\n readonly apollo: InstanceType<typeof ApolloClient>;\n\n constructor(private readonly options: LocalGraphQLClientOptions) {\n const schema = makeExecutableSchema({\n typeDefs,\n resolvers: this.createResolvers(),\n });\n\n this.apollo = new ApolloClient({\n cache: new InMemoryCache(),\n link: new SchemaLink({\n schema,\n context: () => ({\n db: this.options.db,\n storage: this.options.storage,\n pubsub: this.options.pubsub ?? new LocalEventBus(),\n }),\n }),\n devtools: {\n enabled: typeof window !== 'undefined',\n },\n });\n }\n\n private createResolvers() {\n return {\n DateTime: DateTimeScalar,\n Query: {\n taskCategories: async (\n _: ResolverParent,\n args: { projectId: string },\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_task_category WHERE \"projectId\" = $1 ORDER BY name ASC`,\n [args.projectId]\n );\n return result.rows.map(mapTaskCategory);\n },\n tasks: async (\n _: ResolverParent,\n args: { projectId: string },\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_task WHERE \"projectId\" = $1 ORDER BY \"createdAt\" DESC`,\n [args.projectId]\n );\n return result.rows.map(mapTask);\n },\n conversations: async (\n _: ResolverParent,\n args: { projectId: string },\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_conversation WHERE \"projectId\" = $1 ORDER BY \"updatedAt\" DESC`,\n [args.projectId]\n );\n return result.rows.map(mapConversation);\n },\n messages: async (\n _: ResolverParent,\n args: { conversationId: string; limit: number },\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_message WHERE \"conversationId\" = $1 ORDER BY \"createdAt\" DESC LIMIT $2`,\n [args.conversationId, args.limit]\n );\n return result.rows.map(mapMessage);\n },\n recipes: async (\n _: ResolverParent,\n args: { projectId: string; locale: 'EN' | 'FR' },\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_recipe WHERE \"projectId\" = $1 ORDER BY \"nameEn\" ASC`,\n [args.projectId]\n );\n return result.rows.map((row: LocalRow) =>\n mapRecipe(row, args.locale)\n );\n },\n recipe: async (\n _: ResolverParent,\n args: { id: string; locale: 'EN' | 'FR' },\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_recipe WHERE id = $1 LIMIT 1`,\n [args.id]\n );\n if (!result.rows.length || !result.rows[0]) return null;\n return mapRecipe(result.rows[0], args.locale);\n },\n },\n Mutation: {\n createTask: async (\n _: ResolverParent,\n args: { input: Record<string, unknown> },\n ctx: ResolverContext\n ) => {\n const id = generateId('task');\n const now = new Date().toISOString();\n const tags = JSON.stringify(args.input.tags ?? []);\n await ctx.db.execute(\n `INSERT INTO template_task (id, \"projectId\", \"categoryId\", title, description, completed, priority, \"dueDate\", tags, \"createdAt\", \"updatedAt\")\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,\n [\n id,\n args.input.projectId as string,\n (args.input.categoryId as string | undefined) ?? null,\n args.input.title as string,\n (args.input.description as string | undefined) ?? null,\n 0,\n (args.input.priority as string | undefined) ?? 'MEDIUM',\n (args.input.dueDate as string | undefined) ?? null,\n tags,\n now,\n now,\n ]\n );\n const result = await ctx.db.query(\n `SELECT * FROM template_task WHERE id = $1 LIMIT 1`,\n [id]\n );\n if (!result.rows.length || !result.rows[0])\n throw new Error('Failed to create task');\n return mapTask(result.rows[0]);\n },\n updateTask: async (\n _: ResolverParent,\n args: { id: string; input: Record<string, unknown> },\n ctx: ResolverContext\n ) => {\n const now = new Date().toISOString();\n await ctx.db.execute(\n `UPDATE template_task\n SET \"categoryId\" = COALESCE($1, \"categoryId\"),\n title = COALESCE($2, title),\n description = COALESCE($3, description),\n priority = COALESCE($4, priority),\n \"dueDate\" = COALESCE($5, \"dueDate\"),\n tags = COALESCE($6, tags),\n \"updatedAt\" = $7\n WHERE id = $8`,\n [\n (args.input.categoryId as string | undefined) ?? null,\n (args.input.title as string | undefined) ?? null,\n (args.input.description as string | undefined) ?? null,\n (args.input.priority as string | undefined) ?? null,\n (args.input.dueDate as string | undefined) ?? null,\n args.input.tags ? JSON.stringify(args.input.tags) : null,\n now,\n args.id,\n ]\n );\n const result = await ctx.db.query(\n `SELECT * FROM template_task WHERE id = $1 LIMIT 1`,\n [args.id]\n );\n if (!result.rows.length || !result.rows[0])\n throw new Error('Task not found');\n return mapTask(result.rows[0]);\n },\n toggleTask: async (\n _: ResolverParent,\n args: { id: string; completed: boolean },\n ctx: ResolverContext\n ) => {\n const now = new Date().toISOString();\n await ctx.db.execute(\n `UPDATE template_task SET completed = $1, \"updatedAt\" = $2 WHERE id = $3`,\n [args.completed ? 1 : 0, now, args.id]\n );\n const result = await ctx.db.query(\n `SELECT * FROM template_task WHERE id = $1 LIMIT 1`,\n [args.id]\n );\n if (!result.rows.length || !result.rows[0])\n throw new Error('Task not found');\n return mapTask(result.rows[0]);\n },\n deleteTask: async (\n _: ResolverParent,\n args: { id: string },\n ctx: ResolverContext\n ) => {\n await ctx.db.execute(`DELETE FROM template_task WHERE id = $1`, [\n args.id,\n ]);\n return true;\n },\n createConversation: async (\n _: ResolverParent,\n args: { input: Record<string, unknown> },\n ctx: ResolverContext\n ) => {\n const id = generateId('conversation');\n const now = new Date().toISOString();\n await ctx.db.execute(\n `INSERT INTO template_conversation (id, \"projectId\", name, \"isGroup\", \"avatarUrl\", \"updatedAt\")\n VALUES ($1, $2, $3, $4, $5, $6)`,\n [\n id,\n args.input.projectId as string,\n (args.input.name as string | undefined) ?? null,\n (args.input.isGroup as boolean | undefined) ? 1 : 0,\n (args.input.avatarUrl as string | undefined) ?? null,\n now,\n ]\n );\n\n const participants =\n (args.input.participants as Record<string, string>[]) ?? [];\n for (const participant of participants) {\n await ctx.db.execute(\n `INSERT INTO template_conversation_participant (id, \"conversationId\", \"projectId\", \"userId\", \"displayName\", role, \"joinedAt\")\n VALUES ($1, $2, $3, $4, $5, $6, $7)`,\n [\n generateId('participant'),\n id,\n args.input.projectId as string,\n participant.userId,\n participant.displayName ?? null,\n participant.role ?? null,\n now,\n ]\n );\n }\n\n const result = await ctx.db.query(\n `SELECT * FROM template_conversation WHERE id = $1 LIMIT 1`,\n [id]\n );\n if (!result.rows.length || !result.rows[0])\n throw new Error('Failed to create conversation');\n return mapConversation(result.rows[0]);\n },\n sendMessage: async (\n _: ResolverParent,\n args: { input: Record<string, unknown> },\n ctx: ResolverContext\n ) => {\n const id = generateId('message');\n const now = new Date().toISOString();\n await ctx.db.execute(\n `INSERT INTO template_message (id, \"conversationId\", \"projectId\", \"senderId\", \"senderName\", content, attachments, status, \"createdAt\", \"updatedAt\")\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,\n [\n id,\n args.input.conversationId as string,\n args.input.projectId as string,\n args.input.senderId as string,\n (args.input.senderName as string | undefined) ?? null,\n args.input.content as string,\n JSON.stringify([]),\n 'SENT',\n now,\n now,\n ]\n );\n await ctx.db.execute(\n `UPDATE template_conversation SET \"lastMessageId\" = $1, \"updatedAt\" = $2 WHERE id = $3`,\n [id, now, args.input.conversationId as string]\n );\n const result = await ctx.db.query(\n `SELECT * FROM template_message WHERE id = $1`,\n [id]\n );\n if (!result.rows.length || !result.rows[0])\n throw new Error('Failed to send message');\n const message = mapMessage(result.rows[0]);\n ctx.pubsub.emit('message:new', message);\n return message;\n },\n setMessagesRead: async (\n _: ResolverParent,\n args: { conversationId: string; userId: string },\n ctx: ResolverContext\n ) => {\n const now = new Date().toISOString();\n await ctx.db.execute(\n `UPDATE template_conversation_participant\n SET \"lastReadAt\" = $1\n WHERE \"conversationId\" = $2 AND \"userId\" = $3`,\n [now, args.conversationId, args.userId]\n );\n return true;\n },\n favoriteRecipe: async (\n _: ResolverParent,\n args: { id: string; isFavorite: boolean },\n ctx: ResolverContext\n ) => {\n const now = new Date().toISOString();\n await ctx.db.execute(\n `UPDATE template_recipe SET \"isFavorite\" = $1, \"updatedAt\" = $2 WHERE id = $3`,\n [args.isFavorite ? 1 : 0, now, args.id]\n );\n const result = await ctx.db.query(\n `SELECT * FROM template_recipe WHERE id = $1 LIMIT 1`,\n [args.id]\n );\n if (!result.rows.length || !result.rows[0])\n throw new Error('Recipe not found');\n const locale: 'EN' | 'FR' = 'EN';\n return mapRecipe(result.rows[0], locale);\n },\n },\n Task: {\n category: async (\n parent: LocalRow,\n _: unknown,\n ctx: ResolverContext\n ) => {\n if (!parent.categoryId) return null;\n const result = await ctx.db.query(\n `SELECT * FROM template_task_category WHERE id = $1 LIMIT 1`,\n [parent.categoryId]\n );\n if (!result.rows.length || !result.rows[0]) return null;\n return mapTaskCategory(result.rows[0]);\n },\n },\n Conversation: {\n participants: async (\n parent: LocalRow,\n _: unknown,\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_conversation_participant WHERE \"conversationId\" = $1 ORDER BY \"joinedAt\" ASC`,\n [parent.id]\n );\n return result.rows.map(mapParticipant);\n },\n messages: async (\n parent: LocalRow,\n args: { limit: number },\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_message WHERE \"conversationId\" = $1 ORDER BY \"createdAt\" DESC LIMIT $2`,\n [parent.id, args.limit]\n );\n return result.rows.map(mapMessage);\n },\n },\n Recipe: {\n category: async (\n parent: LocalRow & { categoryId?: string | null },\n _: unknown,\n ctx: ResolverContext\n ) => {\n if (!parent.categoryId) return null;\n const result = await ctx.db.query(\n `SELECT * FROM template_recipe_category WHERE id = $1 LIMIT 1`,\n [parent.categoryId]\n );\n if (!result.rows.length || !result.rows[0]) return null;\n return mapRecipeCategory(result.rows[0]);\n },\n ingredients: async (\n parent: LocalRow & { locale: 'EN' | 'FR' },\n _: unknown,\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_recipe_ingredient WHERE \"recipeId\" = $1 ORDER BY ordering ASC`,\n [parent.id]\n );\n return result.rows.map((row: LocalRow) =>\n mapRecipeIngredient(row, parent.locale)\n );\n },\n instructions: async (\n parent: LocalRow & { locale: 'EN' | 'FR' },\n _: unknown,\n ctx: ResolverContext\n ) => {\n const result = await ctx.db.query(\n `SELECT * FROM template_recipe_instruction WHERE \"recipeId\" = $1 ORDER BY ordering ASC`,\n [parent.id]\n );\n return result.rows.map((row: LocalRow) =>\n mapRecipeInstruction(row, parent.locale)\n );\n },\n },\n };\n }\n}\n\nfunction mapTaskCategory(row: LocalRow) {\n return {\n id: row.id,\n projectId: row.projectId,\n name: row.name,\n color: row.color,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapTask(row: LocalRow) {\n return {\n id: row.id,\n projectId: row.projectId,\n categoryId: row.categoryId,\n title: row.title,\n description: row.description,\n completed: Boolean(row.completed),\n priority: row.priority ?? 'MEDIUM',\n dueDate: row.dueDate,\n tags: parseTags(row.tags),\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction parseTags(value: LocalRow['tags']): string[] {\n if (typeof value !== 'string') return [];\n try {\n const parsed = JSON.parse(value);\n return Array.isArray(parsed) ? (parsed as string[]) : [];\n } catch {\n return [];\n }\n}\n\nfunction mapConversation(row: LocalRow) {\n return {\n id: row.id,\n projectId: row.projectId,\n name: row.name,\n isGroup: Boolean(row.isGroup),\n avatarUrl: row.avatarUrl,\n lastMessageId: row.lastMessageId,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapParticipant(row: LocalRow) {\n return {\n id: row.id,\n conversationId: row.conversationId,\n projectId: row.projectId,\n userId: row.userId,\n displayName: row.displayName,\n role: row.role,\n joinedAt: row.joinedAt,\n lastReadAt: row.lastReadAt,\n };\n}\n\nfunction mapMessage(row: LocalRow) {\n return {\n id: row.id,\n conversationId: row.conversationId,\n projectId: row.projectId,\n senderId: row.senderId,\n senderName: row.senderName,\n content: row.content,\n attachments: [],\n status: row.status ?? 'SENT',\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapRecipe(row: LocalRow, locale: 'EN' | 'FR') {\n return {\n id: row.id,\n projectId: row.projectId,\n slugEn: row.slugEn,\n slugFr: row.slugFr,\n name: locale === 'FR' ? row.nameFr : row.nameEn,\n description: locale === 'FR' ? row.descriptionFr : row.descriptionEn,\n heroImageUrl: row.heroImageUrl,\n prepTimeMinutes: row.prepTimeMinutes ?? null,\n cookTimeMinutes: row.cookTimeMinutes ?? null,\n servings: row.servings ?? null,\n isFavorite: Boolean(row.isFavorite),\n locale,\n categoryId: row.categoryId,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n\nfunction mapRecipeCategory(row: LocalRow) {\n return {\n id: row.id,\n nameEn: row.nameEn,\n nameFr: row.nameFr,\n icon: row.icon,\n };\n}\n\nfunction mapRecipeIngredient(row: LocalRow, locale: 'EN' | 'FR') {\n return {\n id: row.id,\n name: locale === 'FR' ? row.nameFr : row.nameEn,\n quantity: row.quantity,\n ordering: row.ordering ?? 0,\n };\n}\n\nfunction mapRecipeInstruction(row: LocalRow, locale: 'EN' | 'FR') {\n return {\n id: row.id,\n content: locale === 'FR' ? row.contentFr : row.contentEn,\n ordering: row.ordering ?? 0,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SANDBOX_MIGRATIONS } from "./database/migrations.js";
|
|
2
|
+
import { agentDefinition, agentRun, agentRunLog, agentRunStep, agentTool, agentToolAssignment, analyticsDashboard, analyticsQuery, analyticsWidget, crmCompany, crmContact, crmDeal, crmPipeline, crmStage, integration, integrationConnection, integrationFieldMapping, integrationSyncConfig, marketplaceOrder, marketplaceOrderItem, marketplacePayout, marketplaceProduct, marketplaceReview, marketplaceStore, psaChangeCandidate, psaReviewTask, psaRule, psaRuleVersion, psaSnapshot, psaUserContext, saasProject, saasSubscription, saasUsage, templateConversation, templateConversationParticipant, templateMessage, templateRecipe, templateRecipeCategory, templateRecipeIngredient, templateRecipeInstruction, templateTask, templateTaskCategory, workflowApproval, workflowDefinition, workflowInstance, workflowStep } from "./database/schema.js";
|
|
3
|
+
import { LocalStorageOptions, LocalStorageService } from "./storage/indexeddb.js";
|
|
4
|
+
import { generateId } from "./utils/id.js";
|
|
5
|
+
import { LocalEventBus } from "./events/local-pubsub.js";
|
|
6
|
+
import { LocalGraphQLClient, LocalGraphQLClientOptions } from "./graphql/local-client.js";
|
|
7
|
+
import { LocalRuntimeInitOptions, LocalRuntimeServices, TemplateId, TemplateSeedOptions } from "./runtime/services.js";
|
|
8
|
+
|
|
9
|
+
//#region src/web/index.d.ts
|
|
10
|
+
declare namespace index_d_exports {
|
|
11
|
+
export { LocalEventBus, LocalGraphQLClient, LocalGraphQLClientOptions, LocalRuntimeInitOptions, LocalRuntimeServices, LocalStorageOptions, LocalStorageService, SANDBOX_MIGRATIONS, TemplateId, TemplateSeedOptions, agentDefinition, agentRun, agentRunLog, agentRunStep, agentTool, agentToolAssignment, analyticsDashboard, analyticsQuery, analyticsWidget, crmCompany, crmContact, crmDeal, crmPipeline, crmStage, generateId, integration, integrationConnection, integrationFieldMapping, integrationSyncConfig, marketplaceOrder, marketplaceOrderItem, marketplacePayout, marketplaceProduct, marketplaceReview, marketplaceStore, psaChangeCandidate, psaReviewTask, psaRule, psaRuleVersion, psaSnapshot, psaUserContext, saasProject, saasSubscription, saasUsage, templateConversation, templateConversationParticipant, templateMessage, templateRecipe, templateRecipeCategory, templateRecipeIngredient, templateRecipeInstruction, templateTask, templateTaskCategory, workflowApproval, workflowDefinition, workflowInstance, workflowStep };
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { index_d_exports };
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|