@stacksjs/commerce 0.75.233 → 0.75.236

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.
@@ -29,6 +29,7 @@ export declare interface ErrorRecord {
29
29
  message: string
30
30
  stack: string | null
31
31
  status: number | null
32
+ resolution: ErrorResolution
32
33
  additional_info: string | null
33
34
  created_at: string
34
35
  updated_at: string | null
@@ -38,7 +39,7 @@ export declare interface GroupedError {
38
39
  type: string
39
40
  message: string
40
41
  stack: string | null
41
- status: string
42
+ status: ErrorResolution
42
43
  count: number
43
44
  first_seen: string
44
45
  last_seen: string
@@ -52,3 +53,4 @@ export declare interface ErrorStats {
52
53
  last_24h: number
53
54
  trend: number
54
55
  }
56
+ export type ErrorResolution = 'unresolved' | 'resolved' | 'ignored';
@@ -1 +1 @@
1
- import{db}from"@stacksjs/database/runtime";export async function fetchById(id){return await db.selectFrom("errors").where("id","=",id).selectAll().executeTakeFirst()}export async function fetchAll(){return await db.selectFrom("errors").selectAll().orderBy("created_at","desc").execute()}export async function fetchGrouped(){const errors=await db.selectFrom("errors").selectAll().orderBy("created_at","desc").execute(),groupMap=new Map;for(const error of errors){const key=`${error.type}:${error.message}`;if(!groupMap.has(key))groupMap.set(key,{errors:[],firstSeen:new Date(error.created_at),lastSeen:new Date(error.created_at)});const group=groupMap.get(key);group.errors.push(error);const errorDate=new Date(error.created_at);if(errorDate<group.firstSeen)group.firstSeen=errorDate;if(errorDate>group.lastSeen)group.lastSeen=errorDate}const groupedErrors=[];for(const[_,group]of groupMap){const representative=group.errors[0];if(!representative)continue;const latestStatus=group.errors.find((e)=>e.status!==null)?.status;let statusLabel="unresolved";if(latestStatus===1)statusLabel="resolved";else if(latestStatus===2)statusLabel="ignored";groupedErrors.push({id:representative.id,type:representative.type,message:representative.message,stack:representative.stack,status:statusLabel,count:group.errors.length,first_seen:group.firstSeen.toISOString(),last_seen:group.lastSeen.toISOString(),error_ids:group.errors.map((e)=>e.id)})}groupedErrors.sort((a,b)=>new Date(b.last_seen).getTime()-new Date(a.last_seen).getTime());return groupedErrors}export async function fetchByGroup(type,message){return await db.selectFrom("errors").where("type","=",type).where("message","=",message).selectAll().orderBy("created_at","desc").execute()}export async function fetchStats(){const errors=await fetchAll(),now=new Date,yesterday=new Date(now.getTime()-86400000),twoDaysAgo=new Date(now.getTime()-172800000),last24h=errors.filter((e)=>new Date(e.created_at)>=yesterday).length,previous24h=errors.filter((e)=>{const date=new Date(e.created_at);return date>=twoDaysAgo&&date<yesterday}).length,trend=previous24h===0?last24h>0?100:0:Math.round((last24h-previous24h)/previous24h*100);return{total:errors.length,unresolved:errors.filter((e)=>e.status===null||e.status===0).length,resolved:errors.filter((e)=>e.status===1).length,ignored:errors.filter((e)=>e.status===2).length,last_24h:last24h,trend}}export async function fetchTimeline(){const errors=await fetchAll(),now=new Date,timeline=[];for(let i=23;i>=0;i--){const hourStart=new Date(now.getTime()-i*60*60*1000);hourStart.setMinutes(0,0,0);const hourEnd=new Date(hourStart.getTime()+3600000),count=errors.filter((e)=>{const date=new Date(e.created_at);return date>=hourStart&&date<hourEnd}).length;timeline.push({hour:hourStart.toISOString(),count})}return timeline}
1
+ import{db}from"@stacksjs/database/runtime";export async function fetchById(id){return await db.selectFrom("errors").where("id","=",id).selectAll().executeTakeFirst()}export async function fetchAll(){return await db.selectFrom("errors").selectAll().orderBy("created_at","desc").execute()}export async function fetchGrouped(){const errors=await db.selectFrom("errors").selectAll().orderBy("created_at","desc").execute(),groupMap=new Map;for(const error of errors){const key=`${error.type}:${error.message}`;if(!groupMap.has(key))groupMap.set(key,{errors:[],firstSeen:new Date(error.created_at),lastSeen:new Date(error.created_at)});const group=groupMap.get(key);group.errors.push(error);const errorDate=new Date(error.created_at);if(errorDate<group.firstSeen)group.firstSeen=errorDate;if(errorDate>group.lastSeen)group.lastSeen=errorDate}const groupedErrors=[];for(const[_,group]of groupMap){const representative=group.errors[0];if(!representative)continue;const statusLabel=representative.resolution??"unresolved";groupedErrors.push({id:representative.id,type:representative.type,message:representative.message,stack:representative.stack,status:statusLabel,count:group.errors.length,first_seen:group.firstSeen.toISOString(),last_seen:group.lastSeen.toISOString(),error_ids:group.errors.map((e)=>e.id)})}groupedErrors.sort((a,b)=>new Date(b.last_seen).getTime()-new Date(a.last_seen).getTime());return groupedErrors}export async function fetchByGroup(type,message){return await db.selectFrom("errors").where("type","=",type).where("message","=",message).selectAll().orderBy("created_at","desc").execute()}export async function fetchStats(){const errors=await fetchAll(),now=new Date,yesterday=new Date(now.getTime()-86400000),twoDaysAgo=new Date(now.getTime()-172800000),last24h=errors.filter((e)=>new Date(e.created_at)>=yesterday).length,previous24h=errors.filter((e)=>{const date=new Date(e.created_at);return date>=twoDaysAgo&&date<yesterday}).length,trend=previous24h===0?last24h>0?100:0:Math.round((last24h-previous24h)/previous24h*100);return{total:errors.length,unresolved:errors.filter((e)=>(e.resolution??"unresolved")==="unresolved").length,resolved:errors.filter((e)=>e.resolution==="resolved").length,ignored:errors.filter((e)=>e.resolution==="ignored").length,last_24h:last24h,trend}}export async function fetchTimeline(){const errors=await fetchAll(),now=new Date,timeline=[];for(let i=23;i>=0;i--){const hourStart=new Date(now.getTime()-i*60*60*1000);hourStart.setMinutes(0,0,0);const hourEnd=new Date(hourStart.getTime()+3600000),count=errors.filter((e)=>{const date=new Date(e.created_at);return date>=hourStart&&date<hourEnd}).length;timeline.push({hour:hourStart.toISOString(),count})}return timeline}
@@ -3,20 +3,24 @@
3
3
  */
4
4
  export declare function update(id: number, data: UpdateErrorData): Promise<boolean>;
5
5
  /**
6
- * Update multiple errors by IDs (for bulk status updates on grouped errors)
6
+ * Set the HTTP status on several errors at once.
7
+ *
8
+ * This is the HTTP status and nothing else. Triage goes through
9
+ * `resolveGroup`, `ignoreGroup` and `unresolveGroup`, which write
10
+ * `resolution` (stacksjs/stacks#2923).
7
11
  */
8
12
  export declare function bulkUpdateStatus(ids: number[], status: number): Promise<boolean>;
9
13
  /**
10
- * Resolve a grouped error (sets status = 1 for all errors in the group)
14
+ * Resolve a grouped error.
15
+ *
16
+ * Writes `resolution`, not `status`. It used to set `status = 1`, which
17
+ * overwrote the HTTP status the error reported and could never be read back
18
+ * as resolved on a seeded row (stacksjs/stacks#2923).
11
19
  */
12
20
  export declare function resolveGroup(type: string, message: string): Promise<boolean>;
13
- /**
14
- * Ignore a grouped error (sets status = 2 for all errors in the group)
15
- */
21
+ /** Ignore a grouped error. Writes `resolution`; see `resolveGroup`. */
16
22
  export declare function ignoreGroup(type: string, message: string): Promise<boolean>;
17
- /**
18
- * Unresolve a grouped error (sets status = 0 for all errors in the group)
19
- */
23
+ /** Return a grouped error to the queue. Writes `resolution`; see `resolveGroup`. */
20
24
  export declare function unresolveGroup(type: string, message: string): Promise<boolean>;
21
25
  export declare interface UpdateErrorData {
22
26
  status?: number
@@ -1 +1 @@
1
- import{db}from"@stacksjs/database/runtime";import{sql}from"@stacksjs/database/runtime";import{log}from"@stacksjs/logging";export async function update(id,data){try{await db.updateTable("errors").set({...data,updated_at:sql.raw("CURRENT_TIMESTAMP")}).where("id","=",id).execute();return!0}catch(error){log.error("[commerce/errors] update failed",{id,error});return!1}}export async function bulkUpdateStatus(ids,status){try{await db.updateTable("errors").set({status,updated_at:sql.raw("CURRENT_TIMESTAMP")}).where("id","in",ids).execute();return!0}catch(error){log.error("[commerce/errors] bulkUpdateStatus failed",{count:ids.length,status,error});return!1}}export async function resolveGroup(type,message){try{await db.updateTable("errors").set({status:1,updated_at:sql.raw("CURRENT_TIMESTAMP")}).where("type","=",type).where("message","=",message).execute();return!0}catch(error){log.error("[commerce/errors] resolveGroup failed",{type,message,error});return!1}}export async function ignoreGroup(type,message){try{await db.updateTable("errors").set({status:2,updated_at:sql.raw("CURRENT_TIMESTAMP")}).where("type","=",type).where("message","=",message).execute();return!0}catch(error){log.error("[commerce/errors] ignoreGroup failed",{type,message,error});return!1}}export async function unresolveGroup(type,message){try{await db.updateTable("errors").set({status:0,updated_at:sql.raw("CURRENT_TIMESTAMP")}).where("type","=",type).where("message","=",message).execute();return!0}catch(error){log.error("[commerce/errors] unresolveGroup failed",{type,message,error});return!1}}
1
+ import{db}from"@stacksjs/database/runtime";import{sql}from"@stacksjs/database/runtime";import{log}from"@stacksjs/logging";export async function update(id,data){try{await db.updateTable("errors").set({...data,updated_at:sql.raw("CURRENT_TIMESTAMP")}).where("id","=",id).execute();return!0}catch(error){log.error("[commerce/errors] update failed",{id,error});return!1}}export async function bulkUpdateStatus(ids,status){try{await db.updateTable("errors").set({status,updated_at:sql.raw("CURRENT_TIMESTAMP")}).where("id","in",ids).execute();return!0}catch(error){log.error("[commerce/errors] bulkUpdateStatus failed",{count:ids.length,status,error});return!1}}export async function resolveGroup(type,message){try{await db.updateTable("errors").set({resolution:"resolved",updated_at:sql.raw("CURRENT_TIMESTAMP")}).where("type","=",type).where("message","=",message).execute();return!0}catch(error){log.error("[commerce/errors] resolveGroup failed",{type,message,error});return!1}}export async function ignoreGroup(type,message){try{await db.updateTable("errors").set({resolution:"ignored",updated_at:sql.raw("CURRENT_TIMESTAMP")}).where("type","=",type).where("message","=",message).execute();return!0}catch(error){log.error("[commerce/errors] ignoreGroup failed",{type,message,error});return!1}}export async function unresolveGroup(type,message){try{await db.updateTable("errors").set({resolution:"unresolved",updated_at:sql.raw("CURRENT_TIMESTAMP")}).where("type","=",type).where("message","=",message).execute();return!0}catch(error){log.error("[commerce/errors] unresolveGroup failed",{type,message,error});return!1}}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/commerce",
3
3
  "type": "module",
4
- "version": "0.75.233",
4
+ "version": "0.75.236",
5
5
  "description": "Stacks commerce utilities.",
6
6
  "author": "Chris Breuer",
7
7
  "contributors": [
@@ -57,18 +57,18 @@
57
57
  "prepublishOnly": "bun run build"
58
58
  },
59
59
  "dependencies": {
60
- "@stacksjs/cache": "0.75.233",
61
- "@stacksjs/config": "0.75.233",
62
- "@stacksjs/database": "0.75.233",
63
- "@stacksjs/env": "0.75.233",
64
- "@stacksjs/error-handling": "0.75.233",
65
- "@stacksjs/events": "0.75.233",
66
- "@stacksjs/logging": "0.75.233",
67
- "@stacksjs/orm": "0.75.233",
68
- "@stacksjs/payments": "0.75.233",
69
- "@stacksjs/realtime": "0.75.233",
70
- "@stacksjs/strings": "0.75.233",
71
- "@stacksjs/validation": "0.75.233",
60
+ "@stacksjs/cache": "0.75.236",
61
+ "@stacksjs/config": "0.75.236",
62
+ "@stacksjs/database": "0.75.236",
63
+ "@stacksjs/env": "0.75.236",
64
+ "@stacksjs/error-handling": "0.75.236",
65
+ "@stacksjs/events": "0.75.236",
66
+ "@stacksjs/logging": "0.75.236",
67
+ "@stacksjs/orm": "0.75.236",
68
+ "@stacksjs/payments": "0.75.236",
69
+ "@stacksjs/realtime": "0.75.236",
70
+ "@stacksjs/strings": "0.75.236",
71
+ "@stacksjs/validation": "0.75.236",
72
72
  "ts-spreadsheets": "^0.2.0"
73
73
  },
74
74
  "devDependencies": {