@glidevvr/storage-payload-error-logger-pkg 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,9 +3,10 @@
3
3
  Centralized error capture for GLI storage products. See the WEB-1413 design doc in `gli-payload-multitenant/docs/plans/2026-05-05-web-1413-error-logger-design.md` for details.
4
4
 
5
5
  ## Subpaths
6
- - `@glidevvr/storage-payload-error-logger-pkg` — core (initLogger, logError, setLogContext, installGlobalHandlers)
6
+ - `@glidevvr/storage-payload-error-logger-pkg` — core browser/Node helper (initLogger, logError, setLogContext, installGlobalHandlers, fingerprint)
7
7
  - `@glidevvr/storage-payload-error-logger-pkg/react` — `<ErrorBoundary>`
8
- - `@glidevvr/storage-payload-error-logger-pkg/payload-endpoint` — Payload v3 `Endpoint` handler
8
+ - `@glidevvr/storage-payload-error-logger-pkg/payload-endpoint` — Payload v3 `Endpoint` handler (the HTTP receiver for browser-side `logError` calls)
9
+ - `@glidevvr/storage-payload-error-logger-pkg/payload-source` — `logFromServer({ req, ... })` for Payload-based servers to log their OWN errors directly via `req.payload.create` (bypasses HTTP / reCAPTCHA / rate-limiting; same destination collection)
9
10
 
10
11
  ## Init
11
12
  `initLogger({ endpoint, repo, release, recaptchaSiteKey })`
@@ -0,0 +1,57 @@
1
+ import { PayloadRequest } from 'payload';
2
+ import { e as Source, d as Repo, S as Severity, R as Reason, L as LogContext } from '../types-BLz-TUBl.cjs';
3
+
4
+ /**
5
+ * Input shape for server-side logging. Mirrors the browser-side `LogEvent`
6
+ * minus the fields that don't make sense server-to-self:
7
+ *
8
+ * - `fingerprint` is recomputed by the IssueEvents dedup hook from
9
+ * (source, message, stack-top-frame, reason). No client-supplied
10
+ * fingerprint to validate.
11
+ * - `userAgent` defaults to "server" — there's no browser involved.
12
+ * - `occurredAt` defaults to now.
13
+ *
14
+ * `tenant` is required: the multi-tenant plugin auto-fills tenant from
15
+ * `req.user.tenants` when a user is present, but server-internal contexts
16
+ * often have no user (scheduled tasks, afterTenantCreated, etc.). Passing
17
+ * tenant explicitly avoids surprises.
18
+ */
19
+ interface LogFromServerEvent {
20
+ source: Source;
21
+ repo: Repo;
22
+ severity?: Severity;
23
+ message: string;
24
+ stack?: string;
25
+ reason?: Reason;
26
+ context?: LogContext;
27
+ url?: string;
28
+ userAgent?: string;
29
+ occurredAt?: string;
30
+ release?: string;
31
+ tenant: string;
32
+ }
33
+ /**
34
+ * Server-side error logger for Payload-based applications.
35
+ *
36
+ * Writes directly to the `issue-events` collection via `req.payload.create`,
37
+ * bypassing the public `/api/log-error` HTTP endpoint. This is the right
38
+ * path for internal CMS errors:
39
+ *
40
+ * - No HTTP roundtrip (server-to-itself is wasteful).
41
+ * - No reCAPTCHA (the public endpoint requires a browser-issued token).
42
+ * - No per-IP / per-tenant rate-limiting (trusted internal call).
43
+ *
44
+ * The same IssueEvents hooks fire as with the HTTP path — dedup, sanitize,
45
+ * severity escalation, regression detection, Slack alerts. The data flow
46
+ * converges at the same destination.
47
+ *
48
+ * **Fire-and-forget.** Any failure during write is swallowed and logged
49
+ * via `req.payload.logger.warn`. The original code path (the thing that
50
+ * called `logFromServer` to report ITS error) should never see a thrown
51
+ * error from this helper.
52
+ */
53
+ declare function logFromServer(opts: {
54
+ req: PayloadRequest;
55
+ } & LogFromServerEvent): Promise<void>;
56
+
57
+ export { type LogFromServerEvent, logFromServer };
@@ -0,0 +1,57 @@
1
+ import { PayloadRequest } from 'payload';
2
+ import { e as Source, d as Repo, S as Severity, R as Reason, L as LogContext } from '../types-BLz-TUBl.js';
3
+
4
+ /**
5
+ * Input shape for server-side logging. Mirrors the browser-side `LogEvent`
6
+ * minus the fields that don't make sense server-to-self:
7
+ *
8
+ * - `fingerprint` is recomputed by the IssueEvents dedup hook from
9
+ * (source, message, stack-top-frame, reason). No client-supplied
10
+ * fingerprint to validate.
11
+ * - `userAgent` defaults to "server" — there's no browser involved.
12
+ * - `occurredAt` defaults to now.
13
+ *
14
+ * `tenant` is required: the multi-tenant plugin auto-fills tenant from
15
+ * `req.user.tenants` when a user is present, but server-internal contexts
16
+ * often have no user (scheduled tasks, afterTenantCreated, etc.). Passing
17
+ * tenant explicitly avoids surprises.
18
+ */
19
+ interface LogFromServerEvent {
20
+ source: Source;
21
+ repo: Repo;
22
+ severity?: Severity;
23
+ message: string;
24
+ stack?: string;
25
+ reason?: Reason;
26
+ context?: LogContext;
27
+ url?: string;
28
+ userAgent?: string;
29
+ occurredAt?: string;
30
+ release?: string;
31
+ tenant: string;
32
+ }
33
+ /**
34
+ * Server-side error logger for Payload-based applications.
35
+ *
36
+ * Writes directly to the `issue-events` collection via `req.payload.create`,
37
+ * bypassing the public `/api/log-error` HTTP endpoint. This is the right
38
+ * path for internal CMS errors:
39
+ *
40
+ * - No HTTP roundtrip (server-to-itself is wasteful).
41
+ * - No reCAPTCHA (the public endpoint requires a browser-issued token).
42
+ * - No per-IP / per-tenant rate-limiting (trusted internal call).
43
+ *
44
+ * The same IssueEvents hooks fire as with the HTTP path — dedup, sanitize,
45
+ * severity escalation, regression detection, Slack alerts. The data flow
46
+ * converges at the same destination.
47
+ *
48
+ * **Fire-and-forget.** Any failure during write is swallowed and logged
49
+ * via `req.payload.logger.warn`. The original code path (the thing that
50
+ * called `logFromServer` to report ITS error) should never see a thrown
51
+ * error from this helper.
52
+ */
53
+ declare function logFromServer(opts: {
54
+ req: PayloadRequest;
55
+ } & LogFromServerEvent): Promise<void>;
56
+
57
+ export { type LogFromServerEvent, logFromServer };
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/payload-source/index.ts
21
+ var payload_source_exports = {};
22
+ __export(payload_source_exports, {
23
+ logFromServer: () => logFromServer
24
+ });
25
+ module.exports = __toCommonJS(payload_source_exports);
26
+ async function logFromServer(opts) {
27
+ const { req, ...event } = opts;
28
+ const now = (/* @__PURE__ */ new Date()).toISOString();
29
+ const data = {
30
+ source: event.source,
31
+ repo: event.repo,
32
+ severity: event.severity ?? "error",
33
+ message: event.message,
34
+ stack: event.stack ?? "",
35
+ reason: event.reason,
36
+ context: event.context ?? {},
37
+ url: event.url ?? "",
38
+ userAgent: event.userAgent ?? "server",
39
+ occurredAt: event.occurredAt ?? now,
40
+ release: event.release,
41
+ tenant: event.tenant
42
+ };
43
+ try {
44
+ await req.payload.create({
45
+ collection: "issue-events",
46
+ data,
47
+ // Thread req so the dedup hook's req.context.triggeringEventContext
48
+ // stash flows to the downstream Slack hooks (same as HTTP-path events).
49
+ req,
50
+ overrideAccess: true
51
+ });
52
+ } catch (err) {
53
+ req.payload.logger.warn(
54
+ { err, source: event.source, message: event.message },
55
+ "logFromServer: failed to write IssueEvent"
56
+ );
57
+ }
58
+ }
59
+ // Annotate the CommonJS export names for ESM import in node:
60
+ 0 && (module.exports = {
61
+ logFromServer
62
+ });
63
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/payload-source/index.ts"],"sourcesContent":["import type { PayloadRequest } from \"payload\";\n\nimport type {\n LogContext,\n Reason,\n Repo,\n Severity,\n Source,\n} from \"../types\";\n\n/**\n * Input shape for server-side logging. Mirrors the browser-side `LogEvent`\n * minus the fields that don't make sense server-to-self:\n *\n * - `fingerprint` is recomputed by the IssueEvents dedup hook from\n * (source, message, stack-top-frame, reason). No client-supplied\n * fingerprint to validate.\n * - `userAgent` defaults to \"server\" — there's no browser involved.\n * - `occurredAt` defaults to now.\n *\n * `tenant` is required: the multi-tenant plugin auto-fills tenant from\n * `req.user.tenants` when a user is present, but server-internal contexts\n * often have no user (scheduled tasks, afterTenantCreated, etc.). Passing\n * tenant explicitly avoids surprises.\n */\nexport interface LogFromServerEvent {\n source: Source;\n repo: Repo;\n severity?: Severity;\n message: string;\n stack?: string;\n reason?: Reason;\n context?: LogContext;\n url?: string;\n userAgent?: string;\n occurredAt?: string;\n release?: string;\n tenant: string;\n}\n\n/**\n * Server-side error logger for Payload-based applications.\n *\n * Writes directly to the `issue-events` collection via `req.payload.create`,\n * bypassing the public `/api/log-error` HTTP endpoint. This is the right\n * path for internal CMS errors:\n *\n * - No HTTP roundtrip (server-to-itself is wasteful).\n * - No reCAPTCHA (the public endpoint requires a browser-issued token).\n * - No per-IP / per-tenant rate-limiting (trusted internal call).\n *\n * The same IssueEvents hooks fire as with the HTTP path — dedup, sanitize,\n * severity escalation, regression detection, Slack alerts. The data flow\n * converges at the same destination.\n *\n * **Fire-and-forget.** Any failure during write is swallowed and logged\n * via `req.payload.logger.warn`. The original code path (the thing that\n * called `logFromServer` to report ITS error) should never see a thrown\n * error from this helper.\n */\nexport async function logFromServer(\n opts: { req: PayloadRequest } & LogFromServerEvent,\n): Promise<void> {\n const { req, ...event } = opts;\n\n const now = new Date().toISOString();\n const data = {\n source: event.source,\n repo: event.repo,\n severity: event.severity ?? \"error\",\n message: event.message,\n stack: event.stack ?? \"\",\n reason: event.reason,\n context: event.context ?? {},\n url: event.url ?? \"\",\n userAgent: event.userAgent ?? \"server\",\n occurredAt: event.occurredAt ?? now,\n release: event.release,\n tenant: event.tenant,\n };\n\n try {\n await req.payload.create({\n collection: \"issue-events\",\n data,\n // Thread req so the dedup hook's req.context.triggeringEventContext\n // stash flows to the downstream Slack hooks (same as HTTP-path events).\n req,\n overrideAccess: true,\n });\n } catch (err) {\n req.payload.logger.warn(\n { err, source: event.source, message: event.message },\n \"logFromServer: failed to write IssueEvent\",\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA4DA,eAAsB,cACpB,MACe;AACf,QAAM,EAAE,KAAK,GAAG,MAAM,IAAI;AAE1B,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,QAAM,OAAO;AAAA,IACX,QAAQ,MAAM;AAAA,IACd,MAAM,MAAM;AAAA,IACZ,UAAU,MAAM,YAAY;AAAA,IAC5B,SAAS,MAAM;AAAA,IACf,OAAO,MAAM,SAAS;AAAA,IACtB,QAAQ,MAAM;AAAA,IACd,SAAS,MAAM,WAAW,CAAC;AAAA,IAC3B,KAAK,MAAM,OAAO;AAAA,IAClB,WAAW,MAAM,aAAa;AAAA,IAC9B,YAAY,MAAM,cAAc;AAAA,IAChC,SAAS,MAAM;AAAA,IACf,QAAQ,MAAM;AAAA,EAChB;AAEA,MAAI;AACF,UAAM,IAAI,QAAQ,OAAO;AAAA,MACvB,YAAY;AAAA,MACZ;AAAA;AAAA;AAAA,MAGA;AAAA,MACA,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,QAAI,QAAQ,OAAO;AAAA,MACjB,EAAE,KAAK,QAAQ,MAAM,QAAQ,SAAS,MAAM,QAAQ;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,38 @@
1
+ // src/payload-source/index.ts
2
+ async function logFromServer(opts) {
3
+ const { req, ...event } = opts;
4
+ const now = (/* @__PURE__ */ new Date()).toISOString();
5
+ const data = {
6
+ source: event.source,
7
+ repo: event.repo,
8
+ severity: event.severity ?? "error",
9
+ message: event.message,
10
+ stack: event.stack ?? "",
11
+ reason: event.reason,
12
+ context: event.context ?? {},
13
+ url: event.url ?? "",
14
+ userAgent: event.userAgent ?? "server",
15
+ occurredAt: event.occurredAt ?? now,
16
+ release: event.release,
17
+ tenant: event.tenant
18
+ };
19
+ try {
20
+ await req.payload.create({
21
+ collection: "issue-events",
22
+ data,
23
+ // Thread req so the dedup hook's req.context.triggeringEventContext
24
+ // stash flows to the downstream Slack hooks (same as HTTP-path events).
25
+ req,
26
+ overrideAccess: true
27
+ });
28
+ } catch (err) {
29
+ req.payload.logger.warn(
30
+ { err, source: event.source, message: event.message },
31
+ "logFromServer: failed to write IssueEvent"
32
+ );
33
+ }
34
+ }
35
+ export {
36
+ logFromServer
37
+ };
38
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/payload-source/index.ts"],"sourcesContent":["import type { PayloadRequest } from \"payload\";\n\nimport type {\n LogContext,\n Reason,\n Repo,\n Severity,\n Source,\n} from \"../types\";\n\n/**\n * Input shape for server-side logging. Mirrors the browser-side `LogEvent`\n * minus the fields that don't make sense server-to-self:\n *\n * - `fingerprint` is recomputed by the IssueEvents dedup hook from\n * (source, message, stack-top-frame, reason). No client-supplied\n * fingerprint to validate.\n * - `userAgent` defaults to \"server\" — there's no browser involved.\n * - `occurredAt` defaults to now.\n *\n * `tenant` is required: the multi-tenant plugin auto-fills tenant from\n * `req.user.tenants` when a user is present, but server-internal contexts\n * often have no user (scheduled tasks, afterTenantCreated, etc.). Passing\n * tenant explicitly avoids surprises.\n */\nexport interface LogFromServerEvent {\n source: Source;\n repo: Repo;\n severity?: Severity;\n message: string;\n stack?: string;\n reason?: Reason;\n context?: LogContext;\n url?: string;\n userAgent?: string;\n occurredAt?: string;\n release?: string;\n tenant: string;\n}\n\n/**\n * Server-side error logger for Payload-based applications.\n *\n * Writes directly to the `issue-events` collection via `req.payload.create`,\n * bypassing the public `/api/log-error` HTTP endpoint. This is the right\n * path for internal CMS errors:\n *\n * - No HTTP roundtrip (server-to-itself is wasteful).\n * - No reCAPTCHA (the public endpoint requires a browser-issued token).\n * - No per-IP / per-tenant rate-limiting (trusted internal call).\n *\n * The same IssueEvents hooks fire as with the HTTP path — dedup, sanitize,\n * severity escalation, regression detection, Slack alerts. The data flow\n * converges at the same destination.\n *\n * **Fire-and-forget.** Any failure during write is swallowed and logged\n * via `req.payload.logger.warn`. The original code path (the thing that\n * called `logFromServer` to report ITS error) should never see a thrown\n * error from this helper.\n */\nexport async function logFromServer(\n opts: { req: PayloadRequest } & LogFromServerEvent,\n): Promise<void> {\n const { req, ...event } = opts;\n\n const now = new Date().toISOString();\n const data = {\n source: event.source,\n repo: event.repo,\n severity: event.severity ?? \"error\",\n message: event.message,\n stack: event.stack ?? \"\",\n reason: event.reason,\n context: event.context ?? {},\n url: event.url ?? \"\",\n userAgent: event.userAgent ?? \"server\",\n occurredAt: event.occurredAt ?? now,\n release: event.release,\n tenant: event.tenant,\n };\n\n try {\n await req.payload.create({\n collection: \"issue-events\",\n data,\n // Thread req so the dedup hook's req.context.triggeringEventContext\n // stash flows to the downstream Slack hooks (same as HTTP-path events).\n req,\n overrideAccess: true,\n });\n } catch (err) {\n req.payload.logger.warn(\n { err, source: event.source, message: event.message },\n \"logFromServer: failed to write IssueEvent\",\n );\n }\n}\n"],"mappings":";AA4DA,eAAsB,cACpB,MACe;AACf,QAAM,EAAE,KAAK,GAAG,MAAM,IAAI;AAE1B,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,QAAM,OAAO;AAAA,IACX,QAAQ,MAAM;AAAA,IACd,MAAM,MAAM;AAAA,IACZ,UAAU,MAAM,YAAY;AAAA,IAC5B,SAAS,MAAM;AAAA,IACf,OAAO,MAAM,SAAS;AAAA,IACtB,QAAQ,MAAM;AAAA,IACd,SAAS,MAAM,WAAW,CAAC;AAAA,IAC3B,KAAK,MAAM,OAAO;AAAA,IAClB,WAAW,MAAM,aAAa;AAAA,IAC9B,YAAY,MAAM,cAAc;AAAA,IAChC,SAAS,MAAM;AAAA,IACf,QAAQ,MAAM;AAAA,EAChB;AAEA,MAAI;AACF,UAAM,IAAI,QAAQ,OAAO;AAAA,MACvB,YAAY;AAAA,MACZ;AAAA;AAAA;AAAA,MAGA;AAAA,MACA,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,QAAI,QAAQ,OAAO;AAAA,MACjB,EAAE,KAAK,QAAQ,MAAM,QAAQ,SAAS,MAAM,QAAQ;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glidevvr/storage-payload-error-logger-pkg",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Centralized error capture for GLI storage products (theme, unit-table, reservation, rental, login). Publishes a runtime helper for browsers and Node, a React error boundary, and a Payload v3 endpoint handler.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -20,6 +20,11 @@
20
20
  "types": "./dist/payload-endpoint/index.d.ts",
21
21
  "import": "./dist/payload-endpoint/index.mjs",
22
22
  "require": "./dist/payload-endpoint/index.js"
23
+ },
24
+ "./payload-source": {
25
+ "types": "./dist/payload-source/index.d.ts",
26
+ "import": "./dist/payload-source/index.mjs",
27
+ "require": "./dist/payload-source/index.js"
23
28
  }
24
29
  },
25
30
  "files": [
@@ -50,6 +55,7 @@
50
55
  "@types/react": "19",
51
56
  "@types/react-dom": "19",
52
57
  "jsdom": "26.1.0",
58
+ "payload": "3.81.0",
53
59
  "react": "19.2.3",
54
60
  "react-dom": "19.2.3",
55
61
  "tsup": "8.5.1",