@flowselections/layout-maker 1.51.4 → 1.53.2

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 (54) hide show
  1. package/README.md +0 -1
  2. package/dist-lib/components/AfdrukKnop.js +64 -64
  3. package/dist-lib/components/LivePrintstatusRegel.d.ts +2 -0
  4. package/dist-lib/components/LivePrintstatusRegel.d.ts.map +1 -0
  5. package/dist-lib/components/LivePrintstatusRegel.js +37 -0
  6. package/dist-lib/components/NetwerkPrintersDialog.js +79 -79
  7. package/dist-lib/components/PrintQueuePage.d.ts.map +1 -1
  8. package/dist-lib/components/PrintQueuePage.js +78 -43
  9. package/dist-lib/components/PrintenPage.d.ts.map +1 -1
  10. package/dist-lib/components/PrintenPage.js +3 -2
  11. package/dist-lib/components/PrintplekDetailPage.d.ts.map +1 -1
  12. package/dist-lib/components/PrintplekDetailPage.js +30 -2
  13. package/dist-lib/index.d.ts +7 -1
  14. package/dist-lib/index.d.ts.map +1 -1
  15. package/dist-lib/index.js +6 -1
  16. package/dist-lib/integrations/supabase/client.server.js +1 -1
  17. package/dist-lib/integrations/supabase/types.d.ts +167 -0
  18. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  19. package/dist-lib/lib/foutTekst.d.ts +10 -0
  20. package/dist-lib/lib/foutTekst.d.ts.map +1 -1
  21. package/dist-lib/lib/foutTekst.js +28 -0
  22. package/dist-lib/lib/printApi.d.ts +33 -0
  23. package/dist-lib/lib/printApi.d.ts.map +1 -1
  24. package/dist-lib/lib/printApi.js +45 -1
  25. package/dist-lib/lib/printQueue.server.d.ts +6 -0
  26. package/dist-lib/lib/printQueue.server.d.ts.map +1 -1
  27. package/dist-lib/lib/printQueue.server.js +72 -20
  28. package/dist-lib/lib/printService.functions.d.ts +76 -0
  29. package/dist-lib/lib/printService.functions.d.ts.map +1 -1
  30. package/dist-lib/lib/printService.functions.js +130 -0
  31. package/dist-lib/lib/printService.server.d.ts +35 -0
  32. package/dist-lib/lib/printService.server.d.ts.map +1 -1
  33. package/dist-lib/lib/printService.server.js +104 -13
  34. package/dist-lib/lib/printnodeStatus.d.ts +14 -0
  35. package/dist-lib/lib/printnodeStatus.d.ts.map +1 -0
  36. package/dist-lib/lib/printnodeStatus.js +43 -0
  37. package/dist-lib/lib/printnodeWebhook.d.ts +23 -0
  38. package/dist-lib/lib/printnodeWebhook.d.ts.map +1 -0
  39. package/dist-lib/lib/printnodeWebhook.js +137 -0
  40. package/dist-lib/lib/printnodeWebhookBeheer.server.d.ts +45 -0
  41. package/dist-lib/lib/printnodeWebhookBeheer.server.d.ts.map +1 -0
  42. package/dist-lib/lib/printnodeWebhookBeheer.server.js +116 -0
  43. package/dist-lib/lib/queueTick.d.ts.map +1 -1
  44. package/dist-lib/lib/queueTick.js +9 -0
  45. package/dist-lib/lib/shellAdres.d.ts +10 -0
  46. package/dist-lib/lib/shellAdres.d.ts.map +1 -0
  47. package/dist-lib/lib/shellAdres.js +36 -0
  48. package/dist-lib/lib/standaardLayouts.server.d.ts +6 -0
  49. package/dist-lib/lib/standaardLayouts.server.d.ts.map +1 -0
  50. package/dist-lib/lib/standaardLayouts.server.js +61 -0
  51. package/dist-lib/lib/useDocumentData.d.ts +10 -1
  52. package/dist-lib/lib/useDocumentData.d.ts.map +1 -1
  53. package/dist-lib/lib/useDocumentData.js +16 -117
  54. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"printService.server.d.ts","sourceRoot":"","sources":["../../src/lib/printService.server.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,oFAAoF;IACpF,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC;IAC1C,oDAAoD;IACpD,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,8BAA8B;IAC9B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAoDD,6EAA6E;AAC7E,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAmBrE;AAED,gFAAgF;AAChF,wBAAsB,mBAAmB,CACvC,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CASzE;AAED,2FAA2F;AAC3F,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBpF;AAED,8EAA8E;AAC9E,wBAAsB,4BAA4B,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKrF;AAGD,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;AAE3E,uDAAuD;AACvD,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAejF;AAED,yCAAyC;AACzC,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAGpD;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED,qDAAqD;AACrD,wBAAsB,aAAa,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAchE"}
1
+ {"version":3,"file":"printService.server.d.ts","sourceRoot":"","sources":["../../src/lib/printService.server.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,34 @@ function b64(tekst) {
19
19
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
20
  return globalThis.Buffer.from(tekst, "utf-8").toString("base64");
21
21
  }
22
+ /** Fout voor een 409 van PrintNode: deze idempotentiesleutel is al ontvangen. */
23
+ export class AlOntvangenFout extends Error {
24
+ constructor() { super("Al ontvangen door de printdienst."); this.name = "AlOntvangenFout"; }
25
+ }
26
+ /** Vaste bronaanduiding; bevat het opdracht-id zodat we hem op id terugvinden. */
27
+ export const SOURCE_PREFIX = "Layouts en printers · ";
28
+ export function sourceVoorJob(jobId) {
29
+ return jobId ? `${SOURCE_PREFIX}${jobId}` : "Layouts en printers";
30
+ }
31
+ /**
32
+ * Standaard vervaltijd per documentsoort (seconden). Vast in de code, geen
33
+ * instellingenscherm. Onbekende soorten: geen expireAfter (PrintNode-standaard).
34
+ */
35
+ export const VERVALTIJD_PER_SOORT = {
36
+ pakbon: 3600,
37
+ productiebon: 3600,
38
+ sticker: 3600,
39
+ verzendbrief: 3600,
40
+ afleverbrief: 3600,
41
+ factuur: 86400,
42
+ };
43
+ export function vervaltijdVoor(documenttype) {
44
+ return VERVALTIJD_PER_SOORT[String(documenttype ?? "").toLowerCase()] ?? null;
45
+ }
46
+ /** PrintNode-aanroep met dezelfde sleutel en child-account-koppen als bij printen. */
47
+ export function printnodeVraag(pad, init) {
48
+ return vraag(pad, init);
49
+ }
22
50
  async function vraag(pad, init) {
23
51
  const toegang = await printToegang();
24
52
  const headers = new Headers(init?.headers);
@@ -46,6 +74,8 @@ async function vraag(pad, init) {
46
74
  vergeetPrintToegang();
47
75
  throw new PrintToegangFout("niet_ingesteld", "De printkoppeling is niet goed ingesteld. Neem contact op met de beheerder.");
48
76
  }
77
+ if (res.status === 409)
78
+ throw new AlOntvangenFout();
49
79
  if (!res.ok) {
50
80
  throw new PrintToegangFout("niet_bereikbaar", "De printdienst is tijdelijk niet bereikbaar. Probeer het zo opnieuw.");
51
81
  }
@@ -90,19 +120,80 @@ export async function stuurPdfNaarPrinter(input) {
90
120
  if (o.rotate === 0 || o.rotate === 90 || o.rotate === 180 || o.rotate === 270) {
91
121
  options["rotate"] = o.rotate;
92
122
  }
93
- const data = await vraag("/printjobs", {
94
- method: "POST",
95
- body: JSON.stringify({
96
- printerId: Number(input.externPrinterId),
97
- title: input.documentnaam.slice(0, 120),
98
- contentType: "pdf_base64",
99
- content: input.pdfBase64,
100
- source: "Layouts en printers",
101
- qty: Math.max(1, Math.min(50, input.kopieen ?? 1)),
102
- options,
103
- }),
104
- });
105
- return String(data);
123
+ const body = {
124
+ printerId: Number(input.externPrinterId),
125
+ title: input.documentnaam.slice(0, 120),
126
+ contentType: "pdf_base64",
127
+ content: input.pdfBase64,
128
+ source: sourceVoorJob(input.jobId),
129
+ qty: Math.max(1, Math.min(50, input.kopieen ?? 1)),
130
+ options,
131
+ };
132
+ if (typeof input.expireAfter === "number" && input.expireAfter > 0) {
133
+ body["expireAfter"] = Math.round(input.expireAfter);
134
+ }
135
+ const headers = {};
136
+ if (input.jobId)
137
+ headers["X-Idempotency-Key"] = input.jobId;
138
+ try {
139
+ const data = await vraag("/printjobs", {
140
+ method: "POST",
141
+ headers,
142
+ body: JSON.stringify(body),
143
+ });
144
+ return String(data);
145
+ }
146
+ catch (e) {
147
+ if (e instanceof AlOntvangenFout && input.jobId) {
148
+ // 409: de opdracht is al ontvangen. Zoek hem op via source (= ons id).
149
+ const bestaand = await zoekPrintJobOpSource(sourceVoorJob(input.jobId));
150
+ if (bestaand)
151
+ return bestaand;
152
+ throw new PrintToegangFout("niet_bereikbaar", "De printdienst had deze opdracht al ontvangen, maar het nummer is (nog) niet terug te vinden. Probeer het zo opnieuw.");
153
+ }
154
+ throw e;
155
+ }
156
+ }
157
+ /**
158
+ * Zoekt een PrintNode-opdracht op exact `source` (bevat print_jobs.id).
159
+ * De lijst staat nieuwste eerst; we bladeren hooguit een paar pagina's.
160
+ */
161
+ export async function zoekPrintJobOpSource(source) {
162
+ let after = null;
163
+ for (let pagina = 0; pagina < 5; pagina++) {
164
+ const q = `/printjobs?limit=100${after ? `&after=${encodeURIComponent(after)}` : ""}`;
165
+ const data = arr(await vraag(q));
166
+ const hit = data.find((j) => j.source === source);
167
+ if (hit)
168
+ return String(hit.id);
169
+ if (data.length < 100)
170
+ return null;
171
+ after = String(data[data.length - 1].id);
172
+ }
173
+ return null;
174
+ }
175
+ export const STABIELE_STATUSSEN = ["new", "sent_to_client", "done", "error", "expired"];
176
+ /** Vertaalt een stabiele PrintNode-status naar de wachtrijstatus. */
177
+ export function wachtrijStatusVoor(s) {
178
+ const t = s.toLowerCase();
179
+ if (t === "done")
180
+ return "voltooid";
181
+ if (t === "error" || t === "expired")
182
+ return "mislukt";
183
+ if (t === "new")
184
+ return "wachtend";
185
+ return "bezig";
186
+ }
187
+ /** Laatste stabiele status + bericht van een opdracht. */
188
+ export async function opdrachtStatusDetail(externJobId) {
189
+ const data = await vraag(`/printjobs/${encodeURIComponent(externJobId)}/states`);
190
+ const groepen = arr(data);
191
+ const states = arr(groepen[groepen.length - 1] ?? []);
192
+ const stabiel = [...states].reverse().find((x) => STABIELE_STATUSSEN.includes(String(x.state ?? "").toLowerCase()));
193
+ const printnode = String(stabiel?.state ?? "").toLowerCase();
194
+ if (!printnode)
195
+ return { printnode: "", bericht: "", status: "bezig" };
196
+ return { printnode, bericht: String(stabiel?.message ?? ""), status: wachtrijStatusVoor(printnode) };
106
197
  }
107
198
  /** Verwijdert een nog niet afgedrukte opdracht bij de externe printdienst. */
108
199
  export async function annuleerExternePrintOpdracht(externJobId) {
@@ -0,0 +1,14 @@
1
+ export declare const PRINTNODE_STATUS_LABEL: Record<string, string>;
2
+ interface JobVoorLabel {
3
+ status: string;
4
+ printnode_status?: string | null;
5
+ foutcode?: string | null;
6
+ }
7
+ /** Label voor de statuskolom van de wachtrij. */
8
+ export declare function printnodeStatusLabel(j: JobVoorLabel): string;
9
+ /** Soorten waarvoor de controlescan van de kar het papier bevestigt. */
10
+ export declare const SCANBARE_SOORTEN: Set<string>;
11
+ /** Is "Opnieuw printen" / "Opnieuw proberen" zinvol voor deze opdracht? */
12
+ export declare function opnieuwActie(j: JobVoorLabel): "opnieuw_proberen" | "opnieuw_printen" | null;
13
+ export {};
14
+ //# sourceMappingURL=printnodeStatus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"printnodeStatus.d.ts","sourceRoot":"","sources":["../../src/lib/printnodeStatus.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMzD,CAAC;AAEF,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,iDAAiD;AACjD,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CAW5D;AAED,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,aAAsD,CAAC;AAEpF,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,CAAC,EAAE,YAAY,GAAG,kBAAkB,GAAG,iBAAiB,GAAG,IAAI,CAI3F"}
@@ -0,0 +1,43 @@
1
+ // ============================================================================
2
+ // src/lib/printnodeStatus.ts — eerlijke weergave van de PrintNode-status.
3
+ // "done" betekent alleen dat het document bij de printerwachtrij van de
4
+ // computer is afgeleverd, niet dat het papier eruit is. Het enige bewijs dat
5
+ // het papier er is, is een goedgekeurde controlescan van de kar.
6
+ // ============================================================================
7
+ export const PRINTNODE_STATUS_LABEL = {
8
+ new: "Aangemaakt",
9
+ sent_to_client: "Naar computer",
10
+ done: "Bij printer afgeleverd",
11
+ error: "Mislukt",
12
+ expired: "Verlopen — niet geprint",
13
+ };
14
+ /** Label voor de statuskolom van de wachtrij. */
15
+ export function printnodeStatusLabel(j) {
16
+ if (j.status === "geannuleerd")
17
+ return "Geannuleerd";
18
+ if (j.foutcode === "AANLEVERING_MISLUKT")
19
+ return "Mislukt — geen document";
20
+ const pn = String(j.printnode_status ?? "").toLowerCase();
21
+ if (pn && PRINTNODE_STATUS_LABEL[pn])
22
+ return PRINTNODE_STATUS_LABEL[pn];
23
+ if (j.status === "wachtend")
24
+ return "Wachtend";
25
+ if (j.status === "bezig")
26
+ return "Bezig";
27
+ if (j.status === "mislukt")
28
+ return "Mislukt";
29
+ // Oude opdrachten zonder PrintNode-status: "voltooid" betekende "verzonden".
30
+ if (j.status === "voltooid")
31
+ return "Bij printer afgeleverd";
32
+ return j.status;
33
+ }
34
+ /** Soorten waarvoor de controlescan van de kar het papier bevestigt. */
35
+ export const SCANBARE_SOORTEN = new Set(["pakbon", "verzendbrief", "afleverbrief"]);
36
+ /** Is "Opnieuw printen" / "Opnieuw proberen" zinvol voor deze opdracht? */
37
+ export function opnieuwActie(j) {
38
+ if (j.foutcode === "AANLEVERING_MISLUKT")
39
+ return "opnieuw_proberen";
40
+ if (j.status === "mislukt" || j.status === "voltooid")
41
+ return "opnieuw_printen";
42
+ return null;
43
+ }
@@ -0,0 +1,23 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ type Db = SupabaseClient<any, any, any>;
3
+ /**
4
+ * PrintNode documenteert alleen dat het secret "in each request" wordt
5
+ * meegestuurd, niet in welk veld. Daarom: is het veld nog niet bekend, dan
6
+ * zoeken we het ENE kopveld waarvan de waarde (in constante tijd) gelijk is
7
+ * aan het secret en leggen alleen die naam vast. Daarna telt alleen dat veld.
8
+ */
9
+ export declare function controleerSecret(request: Request, secret: string, veld: string | null): {
10
+ ok: boolean;
11
+ veld: string | null;
12
+ };
13
+ /** @deprecated gebruik controleerSecret */
14
+ export declare function secretKlopt(request: Request, secret: string): boolean;
15
+ /**
16
+ * Afhandeling van een webhookaanroep. Het geheim komt uit de eigen
17
+ * koppelingstabel (servicerol). `secretVoorTest` alleen voor tests.
18
+ */
19
+ export declare function behandelPrintNodeWebhook(request: Request, db: Db, secretVoorTest?: string): Promise<Response>;
20
+ /** Haalt alle computers op bij PrintNode en slaat hun status op per id. */
21
+ export declare function ververs(db: Db): Promise<number>;
22
+ export {};
23
+ //# sourceMappingURL=printnodeWebhook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"printnodeWebhook.d.ts","sourceRoot":"","sources":["../../src/lib/printnodeWebhook.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,KAAK,EAAE,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAWxC;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GAAG,IAAI,GAClB;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAUtC;AAED,2CAA2C;AAC3C,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAErE;AAOD;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,OAAO,EAChB,EAAE,EAAE,EAAE,EACN,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,QAAQ,CAAC,CAqEnB;AAED,2EAA2E;AAC3E,wBAAsB,OAAO,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBrD"}
@@ -0,0 +1,137 @@
1
+ // ============================================================================
2
+ // src/lib/printnodeWebhook.ts — afhandeling van de PrintNode-webhook.
3
+ // Eén webhook per PrintNode-account; berichten "print job state" en
4
+ // "computer state". De shell levert de databaseverbinding aan.
5
+ //
6
+ // Volgens de PrintNode-documentatie telt een aanroep alleen als gelukt bij een
7
+ // 2xx-antwoord MET de kop "X-PrintNode-Webhook-Status: OK". Zonder die kop
8
+ // probeert PrintNode één keer opnieuw en gooit de melding daarna weg.
9
+ // ============================================================================
10
+ const OK_KOP = { "X-PrintNode-Webhook-Status": "OK" };
11
+ function gelijk(a, b) {
12
+ if (a.length !== b.length)
13
+ return false;
14
+ let verschil = 0;
15
+ for (let i = 0; i < a.length; i++)
16
+ verschil |= a.charCodeAt(i) ^ b.charCodeAt(i);
17
+ return verschil === 0;
18
+ }
19
+ /**
20
+ * PrintNode documenteert alleen dat het secret "in each request" wordt
21
+ * meegestuurd, niet in welk veld. Daarom: is het veld nog niet bekend, dan
22
+ * zoeken we het ENE kopveld waarvan de waarde (in constante tijd) gelijk is
23
+ * aan het secret en leggen alleen die naam vast. Daarna telt alleen dat veld.
24
+ */
25
+ export function controleerSecret(request, secret, veld) {
26
+ if (veld) {
27
+ const w = request.headers.get(veld);
28
+ return { ok: w != null && gelijk(w.trim(), secret), veld };
29
+ }
30
+ const treffers = [];
31
+ request.headers.forEach((waarde, naam) => {
32
+ if (gelijk(waarde.trim(), secret))
33
+ treffers.push(naam.toLowerCase());
34
+ });
35
+ return treffers.length === 1 ? { ok: true, veld: treffers[0] } : { ok: false, veld: null };
36
+ }
37
+ /** @deprecated gebruik controleerSecret */
38
+ export function secretKlopt(request, secret) {
39
+ return controleerSecret(request, secret, null).ok;
40
+ }
41
+ /**
42
+ * Afhandeling van een webhookaanroep. Het geheim komt uit de eigen
43
+ * koppelingstabel (servicerol). `secretVoorTest` alleen voor tests.
44
+ */
45
+ export async function behandelPrintNodeWebhook(request, db, secretVoorTest) {
46
+ let secret = secretVoorTest;
47
+ let veld = null;
48
+ const uitTabel = secretVoorTest === undefined;
49
+ if (uitTabel) {
50
+ try {
51
+ const { data } = await db.from("printnode_webhook_koppeling").select("geheim, secret_veld, status").eq("id", 1).maybeSingle();
52
+ const k = data;
53
+ if (k?.status === "aan" && k.geheim) {
54
+ secret = k.geheim;
55
+ veld = k.secret_veld ?? null;
56
+ }
57
+ }
58
+ catch { /* fail closed */ }
59
+ }
60
+ // Fail closed: zonder koppeling wordt niets verwerkt.
61
+ if (!secret) {
62
+ return Response.json({ ok: false, fout: "Live printstatus is niet gekoppeld." }, { status: 503 });
63
+ }
64
+ const c = controleerSecret(request, secret, veld);
65
+ if (!c.ok)
66
+ return Response.json({ ok: false, fout: "Ongeldig secret" }, { status: 401 });
67
+ if (uitTabel) {
68
+ try {
69
+ await db.from("printnode_webhook_koppeling").update({
70
+ laatst_ontvangen_op: new Date().toISOString(),
71
+ ...(veld ? {} : { secret_veld: c.veld }),
72
+ }).eq("id", 1);
73
+ }
74
+ catch { /* status bijhouden mag verwerking niet blokkeren */ }
75
+ }
76
+ let body;
77
+ try {
78
+ body = await request.json();
79
+ }
80
+ catch {
81
+ return Response.json({ ok: false, fout: "Ongeldige JSON" }, { status: 400 });
82
+ }
83
+ const berichten = Array.isArray(body) ? body : [];
84
+ const { pasPrintNodeStatusToe } = await import("./printQueue.server.js");
85
+ let jobs = 0;
86
+ let computerBericht = false;
87
+ for (const b of berichten.slice(0, 500)) {
88
+ const type = String(b?.type ?? "").toLowerCase();
89
+ if (type === "print job state") {
90
+ const d = b.data ?? {};
91
+ const externId = d["printJobId"];
92
+ const state = String(d["state"] ?? "").toLowerCase();
93
+ if ((typeof externId !== "number" && typeof externId !== "string") || !state)
94
+ continue;
95
+ const { data: job } = await db
96
+ .from("print_jobs")
97
+ .select("id")
98
+ .eq("extern_job_id", String(externId))
99
+ .maybeSingle();
100
+ const id = job?.id;
101
+ if (!id)
102
+ continue;
103
+ await pasPrintNodeStatusToe(db, id, state, String(d["message"] ?? ""));
104
+ jobs++;
105
+ }
106
+ else if (type === "computer state") {
107
+ computerBericht = true;
108
+ }
109
+ }
110
+ // Een computerbericht bevat geen computer-id (alleen hostname). Om op id te
111
+ // matchen halen we de actuele lijst op en slaan die op per computer-id.
112
+ if (computerBericht) {
113
+ try {
114
+ await ververs(db);
115
+ }
116
+ catch (e) {
117
+ console.warn("[printnode-webhook] computerstatus verversen mislukt:", e);
118
+ }
119
+ }
120
+ return Response.json({ ok: true, jobs, computers: computerBericht }, { headers: OK_KOP });
121
+ }
122
+ /** Haalt alle computers op bij PrintNode en slaat hun status op per id. */
123
+ export async function ververs(db) {
124
+ const { haalComputers } = await import("./printService.server.js");
125
+ const computers = await haalComputers();
126
+ if (!computers.length)
127
+ return 0;
128
+ const nu = new Date().toISOString();
129
+ await db.from("print_computer_status").upsert(computers.map((c) => ({
130
+ extern_computer_id: c.id,
131
+ naam: c.naam,
132
+ verbonden: c.online,
133
+ status: c.online ? "connected" : "disconnected",
134
+ bijgewerkt_op: nu,
135
+ })), { onConflict: "extern_computer_id" });
136
+ return computers.length;
137
+ }
@@ -0,0 +1,45 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ type Db = SupabaseClient<any, any, any>;
3
+ export interface Koppeling {
4
+ geheim: string | null;
5
+ secret_veld: string | null;
6
+ webhook_id: number | null;
7
+ url: string | null;
8
+ status: string;
9
+ fout: string | null;
10
+ melding: string | null;
11
+ gekoppeld_op: string | null;
12
+ laatste_poging_op: string | null;
13
+ laatst_ontvangen_op: string | null;
14
+ }
15
+ export declare function leesKoppeling(db: Db): Promise<Koppeling | null>;
16
+ /** Het Shell-adres zoals de Logistiek Engine het bewaart en controleert. */
17
+ export declare function leesShellAdres(db: Db): Promise<string | null>;
18
+ export interface KoppelUitkomst {
19
+ ok: boolean;
20
+ reden?: string;
21
+ url?: string;
22
+ bijgewerkt?: boolean;
23
+ }
24
+ /** Maakt of werkt de webhook bij met een nieuw geheim. */
25
+ export declare function koppelWebhook(db: Db, opties?: {
26
+ oorsprong?: string | null;
27
+ melding?: string | null;
28
+ }): Promise<KoppelUitkomst>;
29
+ /**
30
+ * Wachtrij-ronde: koppel automatisch als er nog geen koppeling is, of werk
31
+ * hem bij als het Shell-adres veranderd is. Na een fout eerst even wachten.
32
+ */
33
+ export declare function zorgVoorWebhookKoppeling(db: Db): Promise<void>;
34
+ /** Veilige status voor het scherm: nooit het geheim. */
35
+ export declare function veiligeStatus(k: Koppeling | null): {
36
+ aan: boolean;
37
+ url: string | null;
38
+ fout: string | null;
39
+ melding: string | null;
40
+ gekoppeldOp: string | null;
41
+ laatstOntvangenOp: string | null;
42
+ veldBevestigd: boolean;
43
+ };
44
+ export {};
45
+ //# sourceMappingURL=printnodeWebhookBeheer.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"printnodeWebhookBeheer.server.d.ts","sourceRoot":"","sources":["../../src/lib/printnodeWebhookBeheer.server.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,KAAK,EAAE,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAQxC,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAID,wBAAsB,aAAa,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAGrE;AAMD,4EAA4E;AAC5E,wBAAsB,cAAc,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAInE;AAQD,MAAM,WAAW,cAAc;IAAG,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE;AAEnG,0DAA0D;AAC1D,wBAAsB,aAAa,CAAC,EAAE,EAAE,EAAE,EAAE,MAAM,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CA4CxI;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBpE;AAED,wDAAwD;AACxD,wBAAgB,aAAa,CAAC,CAAC,EAAE,SAAS,GAAG,IAAI;;;;;;;;EAUhD"}
@@ -0,0 +1,116 @@
1
+ // ============================================================================
2
+ // src/lib/printnodeWebhookBeheer.server.ts — de module koppelt de PrintNode-
3
+ // webhook zelf. Geheim per Shell in de database (alleen servicerol), adres uit
4
+ // de Engine-instelling "shell_base_url". Aanroepen volgens de documentatie:
5
+ // GET /webhooks, POST /webhook, PATCH /webhook/{id}. Max. 5 per account.
6
+ // ============================================================================
7
+ import { beoordeelShellAdres } from "./shellAdres.js";
8
+ const BERICHTEN = ["print job state", "computer state"];
9
+ const MAX_WEBHOOKS = 5;
10
+ /** Na een mislukte poging wacht de automatische koppeling zo lang. */
11
+ const WACHT_NA_FOUT_MIN = 15;
12
+ const TABEL = "printnode_webhook_koppeling";
13
+ export async function leesKoppeling(db) {
14
+ const { data } = await db.from(TABEL).select("*").eq("id", 1).maybeSingle();
15
+ return data ?? null;
16
+ }
17
+ async function schrijf(db, velden) {
18
+ await db.from(TABEL).upsert({ id: 1, ...velden, updated_at: new Date().toISOString() }, { onConflict: "id" });
19
+ }
20
+ /** Het Shell-adres zoals de Logistiek Engine het bewaart en controleert. */
21
+ export async function leesShellAdres(db) {
22
+ const { data } = await db.from("module_runtime_config").select("value").eq("key", "shell_base_url").maybeSingle();
23
+ const v = data?.value;
24
+ return v ? String(v).trim() : null;
25
+ }
26
+ function nieuwGeheim() {
27
+ const b = new Uint8Array(32);
28
+ crypto.getRandomValues(b);
29
+ return Array.from(b, (x) => x.toString(16).padStart(2, "0")).join("");
30
+ }
31
+ /** Maakt of werkt de webhook bij met een nieuw geheim. */
32
+ export async function koppelWebhook(db, opties = {}) {
33
+ const nu = new Date().toISOString();
34
+ const shell = await leesShellAdres(db);
35
+ const oordeel = beoordeelShellAdres(shell ?? opties.oorsprong ?? null);
36
+ if (!oordeel.ok) {
37
+ await schrijf(db, { status: "uit", fout: oordeel.reden, laatste_poging_op: nu });
38
+ return { ok: false, reden: oordeel.reden };
39
+ }
40
+ const { printnodeVraag } = await import("./printService.server.js");
41
+ const geheim = nieuwGeheim();
42
+ try {
43
+ const lijst = await printnodeVraag("/webhooks");
44
+ const alle = Array.isArray(lijst) ? lijst : [];
45
+ const huidig = await leesKoppeling(db);
46
+ // Bestaande webhook: eerst op ons eigen webhookId, anders op exact hetzelfde adres.
47
+ const bestaand = alle.find((w) => huidig?.webhook_id != null && Number(w.webhookId) === Number(huidig.webhook_id)) ??
48
+ alle.find((w) => w.url === oordeel.url);
49
+ let webhookId;
50
+ const body = JSON.stringify({ url: oordeel.url, secret: geheim, messages: BERICHTEN });
51
+ if (bestaand) {
52
+ await printnodeVraag(`/webhook/${Number(bestaand.webhookId)}`, { method: "PATCH", body });
53
+ webhookId = Number(bestaand.webhookId);
54
+ }
55
+ else {
56
+ if (alle.length >= MAX_WEBHOOKS) {
57
+ const reden = `Op dit PrintNode-account staan al ${MAX_WEBHOOKS} webhooks (het maximum). Verwijder er één in PrintNode en druk op "Opnieuw koppelen".`;
58
+ await schrijf(db, { status: "uit", fout: reden, laatste_poging_op: nu });
59
+ return { ok: false, reden };
60
+ }
61
+ const na = await printnodeVraag("/webhook", { method: "POST", body });
62
+ const gevonden = (Array.isArray(na) ? na : []).find((w) => w.url === oordeel.url);
63
+ if (!gevonden)
64
+ throw new Error("PrintNode gaf de nieuwe webhook niet terug.");
65
+ webhookId = Number(gevonden.webhookId);
66
+ }
67
+ await schrijf(db, {
68
+ geheim, secret_veld: null, webhook_id: webhookId, url: oordeel.url, status: "aan",
69
+ fout: null, melding: opties.melding ?? null, gekoppeld_op: nu, laatste_poging_op: nu,
70
+ });
71
+ return { ok: true, url: oordeel.url, bijgewerkt: !!bestaand };
72
+ }
73
+ catch (e) {
74
+ const reden = e instanceof Error ? e.message : "Koppelen mislukt.";
75
+ await schrijf(db, { status: "uit", fout: `Automatisch koppelen lukte niet: ${reden}`, laatste_poging_op: nu });
76
+ return { ok: false, reden };
77
+ }
78
+ }
79
+ /**
80
+ * Wachtrij-ronde: koppel automatisch als er nog geen koppeling is, of werk
81
+ * hem bij als het Shell-adres veranderd is. Na een fout eerst even wachten.
82
+ */
83
+ export async function zorgVoorWebhookKoppeling(db) {
84
+ const huidig = await leesKoppeling(db);
85
+ const shell = await leesShellAdres(db);
86
+ const oordeel = beoordeelShellAdres(shell);
87
+ if (!oordeel.ok) {
88
+ if (!huidig?.webhook_id) {
89
+ if (huidig?.fout !== oordeel.reden)
90
+ await schrijf(db, { status: "uit", fout: oordeel.reden });
91
+ }
92
+ return;
93
+ }
94
+ const gekoppeld = huidig?.status === "aan" && huidig.webhook_id != null && !!huidig.geheim;
95
+ if (gekoppeld && huidig.url === oordeel.url)
96
+ return;
97
+ if (huidig?.fout && huidig.laatste_poging_op &&
98
+ Date.now() - new Date(huidig.laatste_poging_op).getTime() < WACHT_NA_FOUT_MIN * 60000)
99
+ return;
100
+ const gewijzigd = gekoppeld && huidig.url !== oordeel.url;
101
+ await koppelWebhook(db, {
102
+ melding: gewijzigd ? "Shell-adres gewijzigd, de printstatus wordt opnieuw gekoppeld." : null,
103
+ });
104
+ }
105
+ /** Veilige status voor het scherm: nooit het geheim. */
106
+ export function veiligeStatus(k) {
107
+ return {
108
+ aan: k?.status === "aan" && !!k?.geheim,
109
+ url: k?.url ?? null,
110
+ fout: k?.fout ?? null,
111
+ melding: k?.melding ?? null,
112
+ gekoppeldOp: k?.gekoppeld_op ?? null,
113
+ laatstOntvangenOp: k?.laatst_ontvangen_op ?? null,
114
+ veldBevestigd: !!k?.secret_veld,
115
+ };
116
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"queueTick.d.ts","sourceRoot":"","sources":["../../src/lib/queueTick.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,KAAK,EAAE,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAiBxC;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAiFzF"}
1
+ {"version":3,"file":"queueTick.d.ts","sourceRoot":"","sources":["../../src/lib/queueTick.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,KAAK,EAAE,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAiBxC;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyFzF"}
@@ -81,6 +81,15 @@ export async function behandelQueueTick(request, supabase) {
81
81
  return Response.json({ ok: false, fout: configFout }, { status: 500 });
82
82
  }
83
83
  void meldRunnerAan(supabase);
84
+ // Lege shell: standaardlayouts aanmaken (servicerol), zodat een nieuwe klant
85
+ // meteen kan printen zonder dat iemand een pagina opent of op een knop drukt.
86
+ try {
87
+ const { zorgVoorStandaardLayoutsServer } = await import("./standaardLayouts.server.js");
88
+ await zorgVoorStandaardLayoutsServer(supabase);
89
+ }
90
+ catch (e) {
91
+ console.warn("[printwachtrij] standaardlayouts aanmaken mislukt:", e);
92
+ }
84
93
  try {
85
94
  const resultaat = await verwerkWachtrij(supabase, 5);
86
95
  return Response.json({ ok: true, ...resultaat, ontbrekend });
@@ -0,0 +1,10 @@
1
+ export type AdresOordeel = {
2
+ ok: true;
3
+ url: string;
4
+ } | {
5
+ ok: false;
6
+ reden: string;
7
+ };
8
+ export declare const WEBHOOK_PAD = "/api/public/print/printnode-webhook";
9
+ export declare function beoordeelShellAdres(invoer: string | null | undefined): AdresOordeel;
10
+ //# sourceMappingURL=shellAdres.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shellAdres.d.ts","sourceRoot":"","sources":["../../src/lib/shellAdres.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,YAAY,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpF,eAAO,MAAM,WAAW,wCAAwC,CAAC;AAEjE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,YAAY,CA4BnF"}
@@ -0,0 +1,36 @@
1
+ // ============================================================================
2
+ // src/lib/shellAdres.ts — controle of een Shell-adres bruikbaar is voor een
3
+ // webhook. Preview-, dev- en tijdelijke adressen worden geweigerd; gewone
4
+ // gepubliceerde adressen (ook *.lovable.app) en eigen domeinen mogen.
5
+ // ============================================================================
6
+ export const WEBHOOK_PAD = "/api/public/print/printnode-webhook";
7
+ export function beoordeelShellAdres(invoer) {
8
+ const ruw = String(invoer ?? "").trim();
9
+ if (!ruw)
10
+ return { ok: false, reden: "Er is nog geen Shell-adres bekend." };
11
+ let u;
12
+ try {
13
+ u = new URL(ruw);
14
+ }
15
+ catch {
16
+ return { ok: false, reden: `"${ruw}" is geen geldig adres.` };
17
+ }
18
+ const host = u.hostname.toLowerCase();
19
+ if (u.protocol !== "https:")
20
+ return { ok: false, reden: "Het Shell-adres moet met https beginnen." };
21
+ if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local")) {
22
+ return { ok: false, reden: "Een lokaal adres kan PrintNode niet bereiken." };
23
+ }
24
+ if (/^\d{1,3}(\.\d{1,3}){3}$/.test(host) || host.includes(":")) {
25
+ return { ok: false, reden: "Een IP-adres is geen vast Shell-adres." };
26
+ }
27
+ if (host.startsWith("id-preview--") ||
28
+ host.startsWith("preview--") ||
29
+ host.includes("-preview--") ||
30
+ host.endsWith("-dev.lovable.app") ||
31
+ host.endsWith(".lovableproject.com") ||
32
+ host.endsWith(".sandbox.lovable.dev")) {
33
+ return { ok: false, reden: `"${host}" is een preview- of testadres. Gebruik het gepubliceerde Shell-adres.` };
34
+ }
35
+ return { ok: true, url: `${u.protocol}//${u.host}${WEBHOOK_PAD}` };
36
+ }
@@ -0,0 +1,6 @@
1
+ import type { SupabaseClient } from "@supabase/supabase-js";
2
+ type Db = SupabaseClient<any, any, any>;
3
+ /** Geeft het aantal aangemaakte layouts terug (0 als er al layouts waren). */
4
+ export declare function zorgVoorStandaardLayoutsServer(db: Db): Promise<number>;
5
+ export {};
6
+ //# sourceMappingURL=standaardLayouts.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standaardLayouts.server.d.ts","sourceRoot":"","sources":["../../src/lib/standaardLayouts.server.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAI5D,KAAK,EAAE,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAOxC,8EAA8E;AAC9E,wBAAsB,8BAA8B,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA+C5E"}