@powerhousedao/renown-package 0.0.6 → 0.0.30

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.
@@ -27,10 +27,17 @@ export const documentModel = {
27
27
  template: "",
28
28
  },
29
29
  {
30
- code: "MISSING_TYPE",
31
- description: "The type field is required and must include VerifiableCredential",
32
- id: "missing-type-error",
33
- name: "MissingTypeError",
30
+ code: "INVALID_JWT_PAYLOAD",
31
+ description: "JWT payload does not contain valid W3C Verifiable Credential fields",
32
+ id: "invalid-jwt-payload-error",
33
+ name: "InvalidJwtPayloadError",
34
+ template: "",
35
+ },
36
+ {
37
+ code: "JWT_VERIFICATION_FAILED",
38
+ description: "Failed to verify the JWT signature or the JWT is malformed",
39
+ id: "jwt-verification-error",
40
+ name: "JwtVerificationError",
34
41
  template: "",
35
42
  },
36
43
  {
@@ -40,12 +47,19 @@ export const documentModel = {
40
47
  name: "InvalidClaimsError",
41
48
  template: "",
42
49
  },
50
+ {
51
+ code: "MISSING_TYPE",
52
+ description: "The type field is required and must include VerifiableCredential",
53
+ id: "missing-type-error",
54
+ name: "MissingTypeError",
55
+ template: "",
56
+ },
43
57
  ],
44
58
  examples: [],
45
59
  id: "366dfd44-377f-42d7-949d-a8d82b6a909d",
46
60
  name: "INIT",
47
- reducer: '// Validate context\nconst context = action.input.context && action.input.context.length > 0 \n ? action.input.context \n : ["https://www.w3.org/2018/credentials/v1"];\n\nif (!context.includes("https://www.w3.org/2018/credentials/v1")) {\n throw new MissingContextError("Context must include https://www.w3.org/2018/credentials/v1");\n}\n\n// Validate type\nconst type = action.input.type && action.input.type.length > 0\n ? action.input.type\n : ["VerifiableCredential"];\n\nif (!type.includes("VerifiableCredential")) {\n throw new MissingTypeError("Type must include VerifiableCredential");\n}\n\n// Validate credentialSubject is valid JSON\ntry {\n JSON.parse(action.input.credentialSubject);\n} catch (e) {\n throw new InvalidClaimsError("Credential subject must be valid JSON");\n}\n\nstate.context = context;\nstate.id = action.input.id || null;\nstate.type = type;\nstate.issuer = action.input.issuer;\nstate.issuanceDate = action.input.issuanceDate;\nstate.credentialSubject = action.input.credentialSubject;\nstate.expirationDate = action.input.expirationDate || null;\nstate.credentialStatus = null;\nstate.jwt = null;\nstate.revoked = false;\nstate.revokedAt = null;\nstate.revocationReason = null;',
48
- schema: "input InitInput {\n context: [String!]\n id: String\n type: [String!]\n issuer: String!\n issuanceDate: DateTime!\n credentialSubject: String!\n expirationDate: DateTime\n}",
61
+ reducer: "// NOTE: JWT should be cryptographically verified using verifyCredential()\n// from did-jwt-vc BEFORE dispatching this action. This reducer only decodes\n// and extracts the credential fields from the JWT payload.\n\n// Decode the JWT to extract payload\nlet decoded;\ntry {\n decoded = decodeJWT(action.input.jwt);\n} catch (e) {\n const error = e as Error;\n throw new JwtVerificationError(`Failed to decode JWT: ${error.message}`);\n}\n\nconst payload = decoded.payload as JwtPayload;\n\n// Validate minimum required JWT fields\nif (!payload.iss) {\n throw new InvalidJwtPayloadError('JWT payload missing issuer (iss field)');\n}\n\n// Extract the verifiable credential from the payload (if present)\nconst vc = payload.vc as VerifiableCredentialPayload | undefined;\n\nif (!vc) {\n throw new InvalidJwtPayloadError('JWT payload does not contain a verifiable credential (vc field)');\n}\n\n// Store the complete VC payload for maximum flexibility\nstate.vcPayload = JSON.stringify(vc);\n\n// Extract common W3C VC fields if present (but don't fail if missing)\n// Context\nif (vc['@context']) {\n const context = Array.isArray(vc['@context']) ? vc['@context'] : [vc['@context']];\n state.context = context;\n} else {\n state.context = null;\n}\n\n// Type\nif (vc.type) {\n const type = Array.isArray(vc.type) ? vc.type : [vc.type];\n state.type = type;\n} else {\n state.type = null;\n}\n\n// Credential Subject - store as JSON string for flexibility\nif (vc.credentialSubject !== undefined) {\n const credentialSubjectStr = typeof vc.credentialSubject === 'string'\n ? vc.credentialSubject\n : JSON.stringify(vc.credentialSubject);\n state.credentialSubject = credentialSubjectStr;\n} else {\n state.credentialSubject = null;\n}\n\n// Issuer (from JWT payload)\nstate.issuer = payload.iss;\n\n// Issuance date (JWT uses 'iat' or 'nbf')\nif (payload.nbf || payload.iat) {\n const issuanceTimestamp = (payload.nbf || payload.iat)!;\n state.issuanceDate = new Date(issuanceTimestamp * 1000).toISOString();\n} else {\n state.issuanceDate = null;\n}\n\n// Expiration date (from JWT exp or VC expirationDate)\nif (payload.exp) {\n state.expirationDate = new Date(payload.exp * 1000).toISOString();\n} else if (vc.expirationDate) {\n state.expirationDate = vc.expirationDate;\n} else {\n state.expirationDate = null;\n}\n\n// Credential ID (JWT uses 'jti', VC uses 'id')\nstate.id = payload.jti || vc.id || null;\n\n// Credential Status (optional W3C VC field)\nstate.credentialStatus = vc.credentialStatus || null;\n\n// Store JWT token\nstate.jwt = action.input.jwt;\nstate.jwtVerified = true;\n\n// Initialize revocation tracking\nstate.revoked = false;\nstate.revokedAt = null;\nstate.revocationReason = null;",
62
+ schema: "input InitInput {\n jwt: String!\n}",
49
63
  scope: "global",
50
64
  template: "",
51
65
  },
@@ -130,8 +144,8 @@ export const documentModel = {
130
144
  state: {
131
145
  global: {
132
146
  examples: [],
133
- initialValue: '"{\\n \\"context\\": [\\"https://www.w3.org/2018/credentials/v1\\"],\\n \\"id\\": null,\\n \\"type\\": [\\"VerifiableCredential\\"],\\n \\"issuer\\": \\"\\",\\n \\"issuanceDate\\": \\"\\",\\n \\"credentialSubject\\": \\"{}\\",\\n \\"expirationDate\\": null,\\n \\"credentialStatus\\": null,\\n \\"jwt\\": null,\\n \\"revoked\\": false,\\n \\"revokedAt\\": null,\\n \\"revocationReason\\": null\\n}"',
134
- schema: 'type CredentialStatus {\n id: String!\n type: String!\n statusPurpose: String!\n statusListIndex: String!\n statusListCredential: String!\n}\n\ntype RenownCredentialState {\n "W3C VC Required Fields"\n context: [String!]!\n id: String\n type: [String!]!\n issuer: String!\n issuanceDate: DateTime!\n credentialSubject: String!\n \n "W3C VC Optional Fields"\n expirationDate: DateTime\n credentialStatus: CredentialStatus\n \n "JWT Representation"\n jwt: String\n \n "Revocation tracking"\n revoked: Boolean\n revokedAt: DateTime\n revocationReason: String\n}',
147
+ initialValue: '"{\\n \\"vcPayload\\": null,\\n \\"context\\": null,\\n \\"id\\": null,\\n \\"type\\": null,\\n \\"issuer\\": null,\\n \\"issuanceDate\\": null,\\n \\"credentialSubject\\": null,\\n \\"expirationDate\\": null,\\n \\"credentialStatus\\": null,\\n \\"jwt\\": null,\\n \\"jwtVerified\\": false,\\n \\"revoked\\": false,\\n \\"revokedAt\\": null,\\n \\"revocationReason\\": null\\n}"',
148
+ schema: 'type CredentialStatus {\n id: String!\n type: String!\n statusPurpose: String!\n statusListIndex: String!\n statusListCredential: String!\n}\n\ntype RenownCredentialState {\n "JWT token containing the Verifiable Credential"\n jwt: String\n jwtVerified: Boolean\n\n "Complete VC Payload - extracted from JWT for convenience and flexibility"\n vcPayload: String\n\n "W3C VC Common Fields - extracted for querying convenience, may be null for non-standard VCs"\n context: [String!]\n id: String\n type: [String!]\n issuer: String\n issuanceDate: DateTime\n credentialSubject: String\n\n "W3C VC Optional Fields"\n expirationDate: DateTime\n credentialStatus: CredentialStatus\n\n "Revocation tracking"\n revoked: Boolean\n revokedAt: DateTime\n revocationReason: String\n}',
135
149
  },
136
150
  local: {
137
151
  examples: [],
@@ -1,4 +1,4 @@
1
- export type ErrorCode = "MissingContextError" | "MissingTypeError" | "InvalidClaimsError" | "AlreadyRevokedError" | "CredentialRevokedError" | "InvalidStatusPurposeError";
1
+ export type ErrorCode = "MissingContextError" | "InvalidJwtPayloadError" | "JwtVerificationError" | "InvalidClaimsError" | "MissingTypeError" | "AlreadyRevokedError" | "CredentialRevokedError" | "InvalidStatusPurposeError";
2
2
  export interface ReducerError {
3
3
  errorCode: ErrorCode;
4
4
  }
@@ -6,7 +6,11 @@ export declare class MissingContextError extends Error implements ReducerError {
6
6
  errorCode: ErrorCode;
7
7
  constructor(message?: string);
8
8
  }
9
- export declare class MissingTypeError extends Error implements ReducerError {
9
+ export declare class InvalidJwtPayloadError extends Error implements ReducerError {
10
+ errorCode: ErrorCode;
11
+ constructor(message?: string);
12
+ }
13
+ export declare class JwtVerificationError extends Error implements ReducerError {
10
14
  errorCode: ErrorCode;
11
15
  constructor(message?: string);
12
16
  }
@@ -14,6 +18,10 @@ export declare class InvalidClaimsError extends Error implements ReducerError {
14
18
  errorCode: ErrorCode;
15
19
  constructor(message?: string);
16
20
  }
21
+ export declare class MissingTypeError extends Error implements ReducerError {
22
+ errorCode: ErrorCode;
23
+ constructor(message?: string);
24
+ }
17
25
  export declare class AlreadyRevokedError extends Error implements ReducerError {
18
26
  errorCode: ErrorCode;
19
27
  constructor(message?: string);
@@ -29,8 +37,10 @@ export declare class InvalidStatusPurposeError extends Error implements ReducerE
29
37
  export declare const errors: {
30
38
  Init: {
31
39
  MissingContextError: typeof MissingContextError;
32
- MissingTypeError: typeof MissingTypeError;
40
+ InvalidJwtPayloadError: typeof InvalidJwtPayloadError;
41
+ JwtVerificationError: typeof JwtVerificationError;
33
42
  InvalidClaimsError: typeof InvalidClaimsError;
43
+ MissingTypeError: typeof MissingTypeError;
34
44
  };
35
45
  Revoke: {
36
46
  AlreadyRevokedError: typeof AlreadyRevokedError;
@@ -4,9 +4,15 @@ export class MissingContextError extends Error {
4
4
  super(message);
5
5
  }
6
6
  }
7
- export class MissingTypeError extends Error {
8
- errorCode = "MissingTypeError";
9
- constructor(message = "MissingTypeError") {
7
+ export class InvalidJwtPayloadError extends Error {
8
+ errorCode = "InvalidJwtPayloadError";
9
+ constructor(message = "InvalidJwtPayloadError") {
10
+ super(message);
11
+ }
12
+ }
13
+ export class JwtVerificationError extends Error {
14
+ errorCode = "JwtVerificationError";
15
+ constructor(message = "JwtVerificationError") {
10
16
  super(message);
11
17
  }
12
18
  }
@@ -16,6 +22,12 @@ export class InvalidClaimsError extends Error {
16
22
  super(message);
17
23
  }
18
24
  }
25
+ export class MissingTypeError extends Error {
26
+ errorCode = "MissingTypeError";
27
+ constructor(message = "MissingTypeError") {
28
+ super(message);
29
+ }
30
+ }
19
31
  export class AlreadyRevokedError extends Error {
20
32
  errorCode = "AlreadyRevokedError";
21
33
  constructor(message = "AlreadyRevokedError") {
@@ -37,8 +49,10 @@ export class InvalidStatusPurposeError extends Error {
37
49
  export const errors = {
38
50
  Init: {
39
51
  MissingContextError,
40
- MissingTypeError,
52
+ InvalidJwtPayloadError,
53
+ JwtVerificationError,
41
54
  InvalidClaimsError,
55
+ MissingTypeError,
42
56
  },
43
57
  Revoke: {
44
58
  AlreadyRevokedError,
@@ -1,5 +1,5 @@
1
1
  import { BaseDocumentClass } from "document-model";
2
- import { RenownCredentialPHState } from "../ph-factories.js";
2
+ import { type RenownCredentialPHState } from "../ph-factories.js";
3
3
  import { type InitInput, type RevokeInput, type UpdateCredentialSubjectInput, type SetJwtInput, type SetCredentialStatusInput } from "../types.js";
4
4
  export default class RenownCredential_Manager extends BaseDocumentClass<RenownCredentialPHState> {
5
5
  init(input: InitInput): this;
@@ -1,5 +1,5 @@
1
1
  import { BaseDocumentClass, type SignalDispatch } from "document-model";
2
- import { RenownCredentialPHState } from "./ph-factories.js";
2
+ import { type RenownCredentialPHState } from "./ph-factories.js";
3
3
  import RenownCredential_Manager from "./manager/object.js";
4
4
  export * from "./manager/object.js";
5
5
  interface RenownCredential extends RenownCredential_Manager {
@@ -5,15 +5,17 @@ import { createBaseState, defaultBaseState, } from "document-model";
5
5
  import { createDocument } from "./utils.js";
6
6
  export function defaultGlobalState() {
7
7
  return {
8
- context: ["https://www.w3.org/2018/credentials/v1"],
8
+ vcPayload: null,
9
+ context: null,
9
10
  id: null,
10
- type: ["VerifiableCredential"],
11
- issuer: "",
12
- issuanceDate: "",
13
- credentialSubject: "{}",
11
+ type: null,
12
+ issuer: null,
13
+ issuanceDate: null,
14
+ credentialSubject: null,
14
15
  expirationDate: null,
15
16
  credentialStatus: null,
16
17
  jwt: null,
18
+ jwtVerified: false,
17
19
  revoked: false,
18
20
  revokedAt: null,
19
21
  revocationReason: null,
@@ -1,4 +1,4 @@
1
1
  import { type StateReducer } from "document-model";
2
- import { RenownCredentialPHState } from "./ph-factories.js";
2
+ import { type RenownCredentialPHState } from "./ph-factories.js";
3
3
  export declare const stateReducer: StateReducer<RenownCredentialPHState>;
4
4
  export declare const reducer: import("document-model").Reducer<RenownCredentialPHState>;
@@ -142,31 +142,28 @@ export type CredentialStatus = {
142
142
  type: Scalars["String"]["output"];
143
143
  };
144
144
  export type InitInput = {
145
- context?: InputMaybe<Array<Scalars["String"]["input"]>>;
146
- credentialSubject: Scalars["String"]["input"];
147
- expirationDate?: InputMaybe<Scalars["DateTime"]["input"]>;
148
- id?: InputMaybe<Scalars["String"]["input"]>;
149
- issuanceDate: Scalars["DateTime"]["input"];
150
- issuer: Scalars["String"]["input"];
151
- type?: InputMaybe<Array<Scalars["String"]["input"]>>;
145
+ jwt: Scalars["String"]["input"];
152
146
  };
153
147
  export type RenownCredentialState = {
154
- /** W3C VC Required Fields */
155
- context: Array<Scalars["String"]["output"]>;
148
+ /** W3C VC Common Fields - extracted for querying convenience, may be null for non-standard VCs */
149
+ context: Maybe<Array<Scalars["String"]["output"]>>;
156
150
  credentialStatus: Maybe<CredentialStatus>;
157
- credentialSubject: Scalars["String"]["output"];
151
+ credentialSubject: Maybe<Scalars["String"]["output"]>;
158
152
  /** W3C VC Optional Fields */
159
153
  expirationDate: Maybe<Scalars["DateTime"]["output"]>;
160
154
  id: Maybe<Scalars["String"]["output"]>;
161
- issuanceDate: Scalars["DateTime"]["output"];
162
- issuer: Scalars["String"]["output"];
163
- /** JWT Representation */
155
+ issuanceDate: Maybe<Scalars["DateTime"]["output"]>;
156
+ issuer: Maybe<Scalars["String"]["output"]>;
157
+ /** JWT token containing the Verifiable Credential */
164
158
  jwt: Maybe<Scalars["String"]["output"]>;
159
+ jwtVerified: Maybe<Scalars["Boolean"]["output"]>;
165
160
  revocationReason: Maybe<Scalars["String"]["output"]>;
166
161
  /** Revocation tracking */
167
162
  revoked: Maybe<Scalars["Boolean"]["output"]>;
168
163
  revokedAt: Maybe<Scalars["DateTime"]["output"]>;
169
- type: Array<Scalars["String"]["output"]>;
164
+ type: Maybe<Array<Scalars["String"]["output"]>>;
165
+ /** Complete VC Payload - extracted from JWT for convenience and flexibility */
166
+ vcPayload: Maybe<Scalars["String"]["output"]>;
170
167
  };
171
168
  export type RevokeInput = {
172
169
  reason?: InputMaybe<Scalars["String"]["input"]>;
@@ -15,30 +15,26 @@ export function CredentialStatusSchema() {
15
15
  }
16
16
  export function InitInputSchema() {
17
17
  return z.object({
18
- context: z.array(z.string()).nullish(),
19
- credentialSubject: z.string(),
20
- expirationDate: z.string().datetime().nullish(),
21
- id: z.string().nullish(),
22
- issuanceDate: z.string().datetime(),
23
- issuer: z.string(),
24
- type: z.array(z.string()).nullish(),
18
+ jwt: z.string(),
25
19
  });
26
20
  }
27
21
  export function RenownCredentialStateSchema() {
28
22
  return z.object({
29
23
  __typename: z.literal("RenownCredentialState").optional(),
30
- context: z.array(z.string()),
24
+ context: z.array(z.string()).nullable(),
31
25
  credentialStatus: CredentialStatusSchema().nullable(),
32
- credentialSubject: z.string(),
26
+ credentialSubject: z.string().nullable(),
33
27
  expirationDate: z.string().datetime().nullable(),
34
28
  id: z.string().nullable(),
35
- issuanceDate: z.string().datetime(),
36
- issuer: z.string(),
29
+ issuanceDate: z.string().datetime().nullable(),
30
+ issuer: z.string().nullable(),
37
31
  jwt: z.string().nullable(),
32
+ jwtVerified: z.boolean().nullable(),
38
33
  revocationReason: z.string().nullable(),
39
34
  revoked: z.boolean().nullable(),
40
35
  revokedAt: z.string().datetime().nullable(),
41
- type: z.array(z.string()),
36
+ type: z.array(z.string()).nullable(),
37
+ vcPayload: z.string().nullable(),
42
38
  });
43
39
  }
44
40
  export function RevokeInputSchema() {
@@ -1,6 +1,6 @@
1
1
  import { type CreateDocument, type CreateState, type LoadFromFile, type LoadFromInput } from "document-model";
2
2
  import { type RenownCredentialState, type RenownCredentialLocalState } from "./types.js";
3
- import { RenownCredentialPHState } from "./ph-factories.js";
3
+ import { type RenownCredentialPHState } from "./ph-factories.js";
4
4
  export declare const initialGlobalState: RenownCredentialState;
5
5
  export declare const initialLocalState: RenownCredentialLocalState;
6
6
  export declare const createState: CreateState<RenownCredentialPHState>;
@@ -1,15 +1,17 @@
1
1
  import { baseCreateDocument, baseSaveToFile, baseSaveToFileHandle, baseLoadFromFile, baseLoadFromInput, defaultBaseState, generateId, } from "document-model";
2
2
  import { reducer } from "./reducer.js";
3
3
  export const initialGlobalState = {
4
- context: ["https://www.w3.org/2018/credentials/v1"],
4
+ vcPayload: null,
5
+ context: null,
5
6
  id: null,
6
- type: ["VerifiableCredential"],
7
- issuer: "",
8
- issuanceDate: "",
9
- credentialSubject: "{}",
7
+ type: null,
8
+ issuer: null,
9
+ issuanceDate: null,
10
+ credentialSubject: null,
10
11
  expirationDate: null,
11
12
  credentialStatus: null,
12
13
  jwt: null,
14
+ jwtVerified: false,
13
15
  revoked: false,
14
16
  revokedAt: null,
15
17
  revocationReason: null,
@@ -1,36 +1,86 @@
1
- import { InvalidStatusPurposeError, MissingContextError, MissingTypeError, InvalidClaimsError, CredentialRevokedError, AlreadyRevokedError, } from "../../gen/manager/error.js";
1
+ import { InvalidStatusPurposeError, InvalidClaimsError, CredentialRevokedError, AlreadyRevokedError, JwtVerificationError, InvalidJwtPayloadError, } from "../../gen/manager/error.js";
2
+ import { decodeJWT } from 'did-jwt';
2
3
  export const reducer = {
3
4
  initOperation(state, action, dispatch) {
4
- // Validate context
5
- const context = action.input.context && action.input.context.length > 0
6
- ? action.input.context
7
- : ["https://www.w3.org/2018/credentials/v1"];
8
- if (!context.includes("https://www.w3.org/2018/credentials/v1")) {
9
- throw new MissingContextError("Context must include https://www.w3.org/2018/credentials/v1");
10
- }
11
- // Validate type
12
- const type = action.input.type && action.input.type.length > 0
13
- ? action.input.type
14
- : ["VerifiableCredential"];
15
- if (!type.includes("VerifiableCredential")) {
16
- throw new MissingTypeError("Type must include VerifiableCredential");
17
- }
18
- // Validate credentialSubject is valid JSON
5
+ // NOTE: JWT should be cryptographically verified using verifyCredential()
6
+ // from did-jwt-vc BEFORE dispatching this action. This reducer only decodes
7
+ // and extracts the credential fields from the JWT payload.
8
+ // Decode the JWT to extract payload
9
+ let decoded;
19
10
  try {
20
- JSON.parse(action.input.credentialSubject);
11
+ decoded = decodeJWT(action.input.jwt);
21
12
  }
22
13
  catch (e) {
23
- throw new InvalidClaimsError("Credential subject must be valid JSON");
14
+ const error = e;
15
+ throw new JwtVerificationError(`Failed to decode JWT: ${error.message}`);
24
16
  }
25
- state.context = context;
26
- state.id = action.input.id || null;
27
- state.type = type;
28
- state.issuer = action.input.issuer;
29
- state.issuanceDate = action.input.issuanceDate;
30
- state.credentialSubject = action.input.credentialSubject;
31
- state.expirationDate = action.input.expirationDate || null;
32
- state.credentialStatus = null;
33
- state.jwt = null;
17
+ const payload = decoded.payload;
18
+ // Validate minimum required JWT fields
19
+ if (!payload.iss) {
20
+ throw new InvalidJwtPayloadError('JWT payload missing issuer (iss field)');
21
+ }
22
+ // Extract the verifiable credential from the payload (if present)
23
+ const vc = payload.vc;
24
+ if (!vc) {
25
+ throw new InvalidJwtPayloadError('JWT payload does not contain a verifiable credential (vc field)');
26
+ }
27
+ // Store the complete VC payload for maximum flexibility
28
+ state.vcPayload = JSON.stringify(vc);
29
+ // Extract common W3C VC fields if present (but don't fail if missing)
30
+ // Context
31
+ if (vc['@context']) {
32
+ const context = Array.isArray(vc['@context']) ? vc['@context'] : [vc['@context']];
33
+ state.context = context;
34
+ }
35
+ else {
36
+ state.context = null;
37
+ }
38
+ // Type
39
+ if (vc.type) {
40
+ const type = Array.isArray(vc.type) ? vc.type : [vc.type];
41
+ state.type = type;
42
+ }
43
+ else {
44
+ state.type = null;
45
+ }
46
+ // Credential Subject - store as JSON string for flexibility
47
+ if (vc.credentialSubject !== undefined) {
48
+ const credentialSubjectStr = typeof vc.credentialSubject === 'string'
49
+ ? vc.credentialSubject
50
+ : JSON.stringify(vc.credentialSubject);
51
+ state.credentialSubject = credentialSubjectStr;
52
+ }
53
+ else {
54
+ state.credentialSubject = null;
55
+ }
56
+ // Issuer (from JWT payload)
57
+ state.issuer = payload.iss;
58
+ // Issuance date (JWT uses 'iat' or 'nbf')
59
+ if (payload.nbf || payload.iat) {
60
+ const issuanceTimestamp = (payload.nbf || payload.iat);
61
+ state.issuanceDate = new Date(issuanceTimestamp * 1000).toISOString();
62
+ }
63
+ else {
64
+ state.issuanceDate = null;
65
+ }
66
+ // Expiration date (from JWT exp or VC expirationDate)
67
+ if (payload.exp) {
68
+ state.expirationDate = new Date(payload.exp * 1000).toISOString();
69
+ }
70
+ else if (vc.expirationDate) {
71
+ state.expirationDate = vc.expirationDate;
72
+ }
73
+ else {
74
+ state.expirationDate = null;
75
+ }
76
+ // Credential ID (JWT uses 'jti', VC uses 'id')
77
+ state.id = payload.jti || vc.id || null;
78
+ // Credential Status (optional W3C VC field)
79
+ state.credentialStatus = vc.credentialStatus || null;
80
+ // Store JWT token
81
+ state.jwt = action.input.jwt;
82
+ state.jwtVerified = true;
83
+ // Initialize revocation tracking
34
84
  state.revoked = false;
35
85
  state.revokedAt = null;
36
86
  state.revocationReason = null;
@@ -15,25 +15,13 @@ export function Editor(props) {
15
15
  const [isSettingJwt, setIsSettingJwt] = useState(false);
16
16
  const [isSettingStatus, setIsSettingStatus] = useState(false);
17
17
  const { state: { global }, } = typedDocument;
18
- const { context, id: credentialId, type, issuer, issuanceDate, credentialSubject, expirationDate, credentialStatus, jwt, revoked, revokedAt, revocationReason, } = global;
18
+ const { vcPayload, context, id: credentialId, type, issuer, issuanceDate, credentialSubject, expirationDate, credentialStatus, jwt, revoked, revokedAt, revocationReason, } = global;
19
19
  const isInitialized = issuer && issuanceDate;
20
- // Initialize credential
20
+ // Initialize credential from JWT
21
21
  const handleInit = useCallback((values) => {
22
22
  try {
23
- const contextArray = values.context
24
- ? values.context.split(",").map((s) => s.trim())
25
- : undefined;
26
- const typeArray = values.type
27
- ? values.type.split(",").map((s) => s.trim())
28
- : undefined;
29
23
  dispatch(actions.init({
30
- issuer: values.issuer,
31
- issuanceDate: new Date().toISOString(),
32
- credentialSubject: values.credentialSubject,
33
- expirationDate: values.expirationDate || undefined,
34
- context: contextArray,
35
- type: typeArray,
36
- id: values.id,
24
+ jwt: values.jwt,
37
25
  }));
38
26
  setIsInitializing(false);
39
27
  }
@@ -82,16 +70,11 @@ export function Editor(props) {
82
70
  e.preventDefault();
83
71
  const formData = new FormData(e.target);
84
72
  handleInit({
85
- issuer: formData.get("issuer"),
86
- credentialSubject: formData.get("credentialSubject"),
87
- expirationDate: formData.get("expirationDate"),
88
- context: formData.get("context"),
89
- type: formData.get("type"),
90
- id: formData.get("id"),
73
+ jwt: formData.get("jwt"),
91
74
  });
92
- }, children: _jsxs("div", { className: "space-y-6", children: [_jsx(StringField, { name: "issuer", label: "Issuer", required: true, placeholder: "did:example:issuer123", description: "DID or URL of the credential issuer" }), _jsx(TextareaField, { name: "credentialSubject", label: "Credential Subject (JSON)", required: true, placeholder: '{"id": "did:example:subject123", "name": "Alice"}', description: "JSON object containing the claims about the subject", rows: 4 }), _jsx(StringField, { name: "expirationDate", label: "Expiration Date (Optional)", placeholder: "2025-12-31T23:59:59Z", description: "ISO 8601 date when the credential expires" }), _jsx(StringField, { name: "context", label: "Context (Optional)", placeholder: "https://www.w3.org/2018/credentials/v1, https://example.com/contexts/v1", description: "Comma-separated list of context URLs (default: W3C VC context)" }), _jsx(StringField, { name: "type", label: "Type (Optional)", placeholder: "VerifiableCredential, ExampleCredential", description: "Comma-separated list of types (default: VerifiableCredential)" }), _jsx(StringField, { name: "id", label: "Credential ID (Optional)", placeholder: "urn:uuid:...", description: "Unique identifier for this credential" }), _jsx("div", { className: "flex justify-end pt-4", children: _jsx(Button, { type: "submit", children: "Initialize Credential" }) })] }) }) })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "bg-white rounded-xl shadow-md border border-gray-200 overflow-hidden", children: [_jsx("div", { className: "px-6 py-5 bg-gray-50", children: _jsx("h2", { className: "text-2xl font-bold text-gray-900", children: "Credential Information" }) }), _jsxs("div", { className: "p-6", children: [_jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [_jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Credential ID" }), _jsx("p", { className: "text-sm font-mono text-gray-900 break-all", children: credentialId || (_jsx("span", { className: "text-gray-400 italic", children: "Not set" })) })] }), _jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Issuer" }), _jsx("p", { className: "text-sm font-mono text-gray-900 break-all", children: issuer })] }), _jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Issuance Date" }), _jsx("p", { className: "text-sm text-gray-900", children: issuanceDate
75
+ }, children: _jsxs("div", { className: "space-y-6", children: [_jsx(TextareaField, { name: "jwt", label: "JWT (JSON Web Token)", required: true, placeholder: "eyJhbGciOiJFUzI1NksifQ.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmV4YW1wbGU6MTIzIn19LCJzdWIiOiJkaWQ6ZXhhbXBsZToxMjMiLCJuYmYiOjE3MDkyMDAwMDAsImlzcyI6ImRpZDpleGFtcGxlOmlzc3VlciJ9.signature", description: "Paste the signed JWT representing a W3C Verifiable Credential. The JWT should be cryptographically verified before submitting.", rows: 6 }), _jsx("div", { className: "flex justify-end pt-4", children: _jsx(Button, { type: "submit", children: "Initialize Credential from JWT" }) })] }) }) })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "bg-white rounded-xl shadow-md border border-gray-200 overflow-hidden", children: [_jsx("div", { className: "px-6 py-5 bg-gray-50", children: _jsx("h2", { className: "text-2xl font-bold text-gray-900", children: "Credential Information" }) }), _jsxs("div", { className: "p-6", children: [_jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: [_jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Credential ID" }), _jsx("p", { className: "text-sm font-mono text-gray-900 break-all", children: credentialId || (_jsx("span", { className: "text-gray-400 italic", children: "Not set" })) })] }), _jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Issuer" }), _jsx("p", { className: "text-sm font-mono text-gray-900 break-all", children: issuer })] }), _jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Issuance Date" }), _jsx("p", { className: "text-sm text-gray-900", children: issuanceDate
93
76
  ? new Date(issuanceDate).toLocaleString()
94
- : "N/A" })] }), _jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Expiration Date" }), _jsx("p", { className: "text-sm text-gray-900", children: expirationDate ? (new Date(expirationDate).toLocaleString()) : (_jsx("span", { className: "text-gray-400 italic", children: "No expiration" })) })] })] }), _jsxs("div", { className: "mt-6 bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Context" }), _jsx("div", { className: "flex flex-wrap gap-2", children: context && context.map((ctx, i) => (_jsx("span", { className: "inline-block px-2 py-1 text-xs font-mono bg-blue-100 text-blue-800 rounded", children: ctx }, i))) })] }), _jsxs("div", { className: "mt-6 bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Type" }), _jsx("div", { className: "flex flex-wrap gap-2", children: type && type.map((t, i) => (_jsx("span", { className: "inline-block px-2 py-1 text-xs font-mono bg-green-100 text-green-800 rounded", children: t }, i))) })] })] })] }), _jsxs("div", { className: "bg-white rounded-xl shadow-md border border-gray-200 overflow-hidden", children: [_jsx("div", { className: "px-6 py-5 bg-gray-50", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-2xl font-bold text-gray-900", children: "Credential Subject" }), !revoked && !isEditingSubject && (_jsx(Button, { color: "light", onClick: () => setIsEditingSubject(true), children: "Edit Subject" }))] }) }), _jsx("div", { className: "p-6", children: isEditingSubject ? (_jsx(Form, { onSubmit: (e) => {
77
+ : "N/A" })] }), _jsxs("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Expiration Date" }), _jsx("p", { className: "text-sm text-gray-900", children: expirationDate ? (new Date(expirationDate).toLocaleString()) : (_jsx("span", { className: "text-gray-400 italic", children: "No expiration" })) })] })] }), _jsxs("div", { className: "mt-6 bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Context" }), _jsx("div", { className: "flex flex-wrap gap-2", children: context && context.map((ctx, i) => (_jsx("span", { className: "inline-block px-2 py-1 text-xs font-mono bg-blue-100 text-blue-800 rounded", children: ctx }, i))) })] }), _jsxs("div", { className: "mt-6 bg-gray-50 p-4 rounded-lg border border-gray-200", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Type" }), _jsx("div", { className: "flex flex-wrap gap-2", children: type && type.map((t, i) => (_jsx("span", { className: "inline-block px-2 py-1 text-xs font-mono bg-green-100 text-green-800 rounded", children: t }, i))) })] })] })] }), vcPayload && (_jsxs("div", { className: "bg-white rounded-xl shadow-md border border-gray-200 overflow-hidden", children: [_jsxs("div", { className: "px-6 py-5 bg-purple-50", children: [_jsx("h2", { className: "text-2xl font-bold text-gray-900", children: "Complete Verifiable Credential" }), _jsx("p", { className: "text-sm text-gray-600 mt-1", children: "Full VC payload from JWT - supports any W3C VC structure" })] }), _jsx("div", { className: "p-6", children: _jsx("pre", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200 overflow-auto text-sm max-h-96", children: JSON.stringify(JSON.parse(vcPayload), null, 2) }) })] })), _jsxs("div", { className: "bg-white rounded-xl shadow-md border border-gray-200 overflow-hidden", children: [_jsx("div", { className: "px-6 py-5 bg-gray-50", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-2xl font-bold text-gray-900", children: "Credential Subject" }), !revoked && !isEditingSubject && (_jsx(Button, { color: "light", onClick: () => setIsEditingSubject(true), children: "Edit Subject" }))] }) }), _jsx("div", { className: "p-6", children: isEditingSubject ? (_jsx(Form, { onSubmit: (e) => {
95
78
  e.preventDefault();
96
79
  const formData = new FormData(e.target);
97
80
  handleUpdateSubject(formData.get("credentialSubject"));
@@ -99,7 +82,7 @@ export function Editor(props) {
99
82
  e.preventDefault();
100
83
  const formData = new FormData(e.target);
101
84
  handleSetJwt(formData.get("jwt"));
102
- }, children: _jsxs("div", { className: "space-y-4", children: [_jsx(TextareaField, { name: "jwt", label: "JWT Token", defaultValue: jwt || "", required: true, rows: 6, description: "Signed JWT representation of the credential" }), _jsxs("div", { className: "flex justify-end space-x-3", children: [_jsx(Button, { color: "light", onClick: () => setIsSettingJwt(false), children: "Cancel" }), _jsx(Button, { type: "submit", children: "Set JWT" })] })] }) })) : jwt ? (_jsx("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: _jsx("p", { className: "text-xs font-mono text-gray-900 break-all", children: jwt }) })) : (_jsx("p", { className: "text-gray-500 italic", children: "No JWT set" })) })] }), _jsxs("div", { className: "bg-white rounded-xl shadow-md border border-gray-200 overflow-hidden", children: [_jsx("div", { className: "px-6 py-5 bg-gray-50", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-2xl font-bold text-gray-900", children: "Credential Status (StatusList2021)" }), !credentialStatus && !isSettingStatus && (_jsx(Button, { color: "light", onClick: () => setIsSettingStatus(true), children: "Set Status" }))] }) }), _jsx("div", { className: "p-6", children: isSettingStatus ? (_jsx(Form, { onSubmit: (e) => {
85
+ }, children: _jsxs("div", { className: "space-y-4", children: [_jsx(TextareaField, { name: "jwt", label: "JWT Token", defaultValue: jwt || "", required: true, rows: 6, description: "Signed JWT representation of the credential" }), _jsxs("div", { className: "flex justify-end space-x-3", children: [_jsx(Button, { color: "light", onClick: () => setIsSettingJwt(false), children: "Cancel" }), _jsx(Button, { type: "submit", children: "Set JWT" })] })] }) })) : jwt ? (_jsx(_Fragment, { children: _jsx("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200", children: _jsx("p", { className: "text-xs font-mono text-gray-900 break-all", children: jwt }) }) })) : (_jsx("p", { className: "text-gray-500 italic", children: "No JWT set" })) })] }), _jsxs("div", { className: "bg-white rounded-xl shadow-md border border-gray-200 overflow-hidden", children: [_jsx("div", { className: "px-6 py-5 bg-gray-50", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-2xl font-bold text-gray-900", children: "Credential Status (StatusList2021)" }), !credentialStatus && !isSettingStatus && (_jsx(Button, { color: "light", onClick: () => setIsSettingStatus(true), children: "Set Status" }))] }) }), _jsx("div", { className: "p-6", children: isSettingStatus ? (_jsx(Form, { onSubmit: (e) => {
103
86
  e.preventDefault();
104
87
  const formData = new FormData(e.target);
105
88
  handleSetStatus({
@@ -27,30 +27,37 @@ export class RenownCredentialProcessor extends RelationalDbProcessor {
27
27
  for (const operation of strand.operations) {
28
28
  switch (operation.action.type) {
29
29
  case "INIT": {
30
- const input = operation.action.input;
31
- if (input && !existingCredential) {
30
+ // INIT operation now only receives JWT, all fields are extracted by the reducer
31
+ // Access the document state to get the extracted fields
32
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
33
+ const state = (strand.state)?.global;
34
+ if (state && !existingCredential) {
32
35
  await this.relationalDb
33
36
  .insertInto("renown_credential")
34
37
  .values({
35
38
  document_id: documentId,
36
- context: JSON.stringify(input.context || ["https://www.w3.org/2018/credentials/v1"]),
37
- credential_id: input.id || null,
38
- type: JSON.stringify(input.type || ["VerifiableCredential"]),
39
- issuer: input.issuer,
40
- issuance_date: new Date(input.issuanceDate),
41
- credential_subject: input.credentialSubject,
42
- expiration_date: input.expirationDate
43
- ? new Date(input.expirationDate)
39
+ jwt: state.jwt || null,
40
+ jwt_verified: state.jwtVerified || false,
41
+ vc_payload: state.vcPayload || null,
42
+ context: state.context ? JSON.stringify(state.context) : null,
43
+ credential_id: state.id || null,
44
+ type: state.type ? JSON.stringify(state.type) : null,
45
+ issuer: state.issuer || null,
46
+ issuance_date: state.issuanceDate
47
+ ? new Date(state.issuanceDate)
48
+ : null,
49
+ credential_subject: state.credentialSubject || null,
50
+ expiration_date: state.expirationDate
51
+ ? new Date(state.expirationDate)
44
52
  : null,
45
- credential_status_id: null,
46
- credential_status_type: null,
47
- credential_status_purpose: null,
48
- credential_status_list_index: null,
49
- credential_status_list_credential: null,
50
- jwt: null,
51
- revoked: false,
52
- revoked_at: null,
53
- revocation_reason: null,
53
+ credential_status_id: state.credentialStatus?.id || null,
54
+ credential_status_type: state.credentialStatus?.type || null,
55
+ credential_status_purpose: state.credentialStatus?.statusPurpose || null,
56
+ credential_status_list_index: state.credentialStatus?.statusListIndex || null,
57
+ credential_status_list_credential: state.credentialStatus?.statusListCredential || null,
58
+ revoked: state.revoked || false,
59
+ revoked_at: state.revokedAt ? new Date(state.revokedAt) : null,
60
+ revocation_reason: state.revocationReason || null,
54
61
  created_at: new Date(),
55
62
  updated_at: new Date(),
56
63
  })
@@ -59,13 +66,17 @@ export class RenownCredentialProcessor extends RelationalDbProcessor {
59
66
  break;
60
67
  }
61
68
  case "UPDATE_CREDENTIAL_SUBJECT": {
62
- const input = operation.action.input;
63
- if (input && existingCredential) {
69
+ // Access the updated state to get the synced vcPayload
70
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
71
+ const state = (strand.state)?.global;
72
+ if (state && existingCredential) {
64
73
  await this.relationalDb
65
74
  .updateTable("renown_credential")
66
75
  .set({
67
- credential_subject: input.credentialSubject,
76
+ credential_subject: state.credentialSubject || null,
77
+ vc_payload: state.vcPayload || null, // Sync vcPayload with updated credentialSubject
68
78
  jwt: null, // Clear JWT when content changes
79
+ jwt_verified: false, // Mark as unverified since content changed
69
80
  updated_at: new Date(),
70
81
  })
71
82
  .where("document_id", "=", documentId)
@@ -1,22 +1,24 @@
1
1
  export async function up(db) {
2
2
  await down(db);
3
- // Create renown_credential table
3
+ // Create renown_credential table with flexible VC schema support
4
4
  await db.schema
5
5
  .createTable("renown_credential")
6
6
  .addColumn("document_id", "varchar(255)")
7
- .addColumn("context", "text") // JSON array
7
+ .addColumn("jwt", "text") // JWT token containing the VC
8
+ .addColumn("jwt_verified", "boolean", (col) => col.notNull().defaultTo(false))
9
+ .addColumn("vc_payload", "text") // Complete VC JSON object extracted from JWT
10
+ .addColumn("context", "text") // JSON array - extracted for convenience
8
11
  .addColumn("credential_id", "varchar(255)")
9
- .addColumn("type", "text") // JSON array
10
- .addColumn("issuer", "varchar(255)", (col) => col.notNull())
11
- .addColumn("issuance_date", "timestamp", (col) => col.notNull())
12
- .addColumn("credential_subject", "text", (col) => col.notNull()) // JSON object
12
+ .addColumn("type", "text") // JSON array - extracted for convenience
13
+ .addColumn("issuer", "varchar(255)") // Now nullable to support any VC structure
14
+ .addColumn("issuance_date", "timestamp") // Now nullable
15
+ .addColumn("credential_subject", "text") // JSON object - now nullable
13
16
  .addColumn("expiration_date", "timestamp")
14
17
  .addColumn("credential_status_id", "varchar(255)")
15
18
  .addColumn("credential_status_type", "varchar(255)")
16
19
  .addColumn("credential_status_purpose", "varchar(255)")
17
20
  .addColumn("credential_status_list_index", "varchar(255)")
18
21
  .addColumn("credential_status_list_credential", "text")
19
- .addColumn("jwt", "text")
20
22
  .addColumn("revoked", "boolean", (col) => col.notNull().defaultTo(false))
21
23
  .addColumn("revoked_at", "timestamp")
22
24
  .addColumn("revocation_reason", "text")
@@ -3,19 +3,21 @@ export type Generated<T> = T extends ColumnType<infer S, infer I, infer U> ? Col
3
3
  export type Timestamp = ColumnType<Date, Date | string, Date | string>;
4
4
  export interface RenownCredential {
5
5
  document_id: string;
6
- context: string;
6
+ jwt: string | null;
7
+ jwt_verified: boolean;
8
+ vc_payload: string | null;
9
+ context: string | null;
7
10
  credential_id: string | null;
8
- type: string;
9
- issuer: string;
10
- issuance_date: Timestamp;
11
- credential_subject: string;
11
+ type: string | null;
12
+ issuer: string | null;
13
+ issuance_date: Timestamp | null;
14
+ credential_subject: string | null;
12
15
  expiration_date: Timestamp | null;
13
16
  credential_status_id: string | null;
14
17
  credential_status_type: string | null;
15
18
  credential_status_purpose: string | null;
16
19
  credential_status_list_index: string | null;
17
20
  credential_status_list_credential: string | null;
18
- jwt: string | null;
19
21
  revoked: boolean;
20
22
  revoked_at: Timestamp | null;
21
23
  revocation_reason: string | null;
package/dist/style.css CHANGED
@@ -61,6 +61,7 @@
61
61
  --color-blue-900: oklch(37.9% 0.146 265.522);
62
62
  --color-indigo-50: oklch(96.2% 0.018 272.314);
63
63
  --color-indigo-800: oklch(39.8% 0.195 277.366);
64
+ --color-purple-50: oklch(97.7% 0.014 308.299);
64
65
  --color-purple-800: oklch(43.8% 0.218 303.724);
65
66
  --color-purple-900: oklch(38.1% 0.176 304.987);
66
67
  --color-pink-400: oklch(71.8% 0.202 349.761);
@@ -361,6 +362,9 @@
361
362
  .h-24 {
362
363
  height: calc(var(--spacing) * 24);
363
364
  }
365
+ .max-h-96 {
366
+ max-height: calc(var(--spacing) * 96);
367
+ }
364
368
  .min-h-screen {
365
369
  min-height: 100vh;
366
370
  }
@@ -526,6 +530,9 @@
526
530
  .bg-green-100 {
527
531
  background-color: var(--color-green-100);
528
532
  }
533
+ .bg-purple-50 {
534
+ background-color: var(--color-purple-50);
535
+ }
529
536
  .bg-red-50 {
530
537
  background-color: var(--color-red-50);
531
538
  }
@@ -12,21 +12,25 @@ export const schema = gql `
12
12
  }
13
13
 
14
14
  type RenownCredentialState {
15
- "W3C VC Required Fields"
16
- context: [String!]!
15
+ "JWT token containing the Verifiable Credential"
16
+ jwt: String
17
+ jwtVerified: Boolean
18
+
19
+ "Complete VC Payload - extracted from JWT for convenience and flexibility"
20
+ vcPayload: String
21
+
22
+ "W3C VC Common Fields - extracted for querying convenience, may be null for non-standard VCs"
23
+ context: [String!]
17
24
  id: String
18
- type: [String!]!
19
- issuer: String!
20
- issuanceDate: DateTime!
21
- credentialSubject: String!
25
+ type: [String!]
26
+ issuer: String
27
+ issuanceDate: DateTime
28
+ credentialSubject: String
22
29
 
23
30
  "W3C VC Optional Fields"
24
31
  expirationDate: DateTime
25
32
  credentialStatus: CredentialStatus
26
33
 
27
- "JWT Representation"
28
- jwt: String
29
-
30
34
  "Revocation tracking"
31
35
  revoked: Boolean
32
36
  revokedAt: DateTime
@@ -82,13 +86,7 @@ export const schema = gql `
82
86
  Module: Manager
83
87
  """
84
88
  input RenownCredential_InitInput {
85
- context: [String!]
86
- id: String
87
- type: [String!]
88
- issuer: String!
89
- issuanceDate: DateTime!
90
- credentialSubject: String!
91
- expirationDate: DateTime
89
+ jwt: String!
92
90
  }
93
91
  input RenownCredential_RevokeInput {
94
92
  revokedAt: DateTime!
@@ -10,9 +10,12 @@ const mapToUser = (user) => ({
10
10
  });
11
11
  const mapToCredential = (credential) => ({
12
12
  documentId: credential.document_id,
13
+ jwt: credential.jwt,
14
+ jwtVerified: credential.jwt_verified,
15
+ vcPayload: credential.vc_payload,
13
16
  credentialId: credential.credential_id,
14
- context: JSON.parse(credential.context),
15
- type: JSON.parse(credential.type),
17
+ context: credential.context ? JSON.parse(credential.context) : null,
18
+ type: credential.type ? JSON.parse(credential.type) : null,
16
19
  issuer: credential.issuer,
17
20
  issuanceDate: credential.issuance_date,
18
21
  credentialSubject: credential.credential_subject,
@@ -30,7 +33,6 @@ const mapToCredential = (credential) => ({
30
33
  statusListCredential: credential.credential_status_list_credential,
31
34
  }
32
35
  : null,
33
- jwt: credential.jwt,
34
36
  revoked: credential.revoked,
35
37
  revokedAt: credential.revoked_at,
36
38
  revocationReason: credential.revocation_reason,
@@ -28,15 +28,17 @@ export const schema = gql `
28
28
 
29
29
  type ReadRenownCredential {
30
30
  documentId: String!
31
+ jwt: String
32
+ jwtVerified: Boolean!
33
+ vcPayload: String
31
34
  credentialId: String
32
- context: [String!]!
33
- type: [String!]!
34
- issuer: String!
35
- issuanceDate: DateTime!
36
- credentialSubject: String!
35
+ context: [String!]
36
+ type: [String!]
37
+ issuer: String
38
+ issuanceDate: DateTime
39
+ credentialSubject: String
37
40
  expirationDate: DateTime
38
41
  credentialStatus: ReadCredentialStatus
39
- jwt: String
40
42
  revoked: Boolean!
41
43
  revokedAt: DateTime
42
44
  revocationReason: String
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powerhousedao/renown-package",
3
3
  "description": "",
4
- "version": "0.0.6",
4
+ "version": "0.0.30",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",
7
7
  "files": [
@@ -62,12 +62,14 @@
62
62
  "./style.css": "./dist/style.css"
63
63
  },
64
64
  "dependencies": {
65
- "@powerhousedao/builder-tools": "staging",
66
- "@powerhousedao/common": "staging",
67
- "@powerhousedao/design-system": "staging",
65
+ "@powerhousedao/builder-tools": "5.0.0-staging.30",
66
+ "@powerhousedao/common": "5.0.0-staging.30",
67
+ "@powerhousedao/design-system": "5.0.0-staging.30",
68
68
  "@powerhousedao/document-engineering": "^1.37.0",
69
- "@powerhousedao/vetra": "staging",
70
- "document-model": "staging",
69
+ "@powerhousedao/vetra": "5.0.0-staging.30",
70
+ "did-jwt": "^8.0.18",
71
+ "did-jwt-vc": "^4.0.16",
72
+ "document-model": "5.0.0-staging.30",
71
73
  "graphql": "^16.10.0",
72
74
  "graphql-tag": "^2.12.6",
73
75
  "kysely": "^0.28.7",
@@ -79,13 +81,13 @@
79
81
  "@electric-sql/pglite": "^0.2.12",
80
82
  "@eslint/js": "^9.22.0",
81
83
  "@powerhousedao/analytics-engine-core": "^0.5.0",
82
- "@powerhousedao/codegen": "staging",
83
- "@powerhousedao/ph-cli": "staging",
84
- "@powerhousedao/reactor-api": "staging",
85
- "@powerhousedao/reactor-browser": "staging",
86
- "@powerhousedao/reactor-local": "staging",
87
- "@powerhousedao/scalars": "staging",
88
- "@powerhousedao/switchboard": "staging",
84
+ "@powerhousedao/codegen": "5.0.0-staging.30",
85
+ "@powerhousedao/ph-cli": "5.0.0-staging.30",
86
+ "@powerhousedao/reactor-api": "5.0.0-staging.30",
87
+ "@powerhousedao/reactor-browser": "5.0.0-staging.30",
88
+ "@powerhousedao/reactor-local": "5.0.0-staging.30",
89
+ "@powerhousedao/scalars": "1.33.1-staging.5",
90
+ "@powerhousedao/switchboard": "5.0.0-staging.30",
89
91
  "@semantic-release/changelog": "^6.0.3",
90
92
  "@semantic-release/git": "^10.0.1",
91
93
  "@tailwindcss/cli": "^4.0.15",
@@ -93,7 +95,7 @@
93
95
  "@types/node": "^22.13.11",
94
96
  "@types/react": "^18.3.19",
95
97
  "@vitejs/plugin-react": "^4.3.4",
96
- "document-drive": "staging",
98
+ "document-drive": "5.0.0-staging.30",
97
99
  "eslint": "^9.22.0",
98
100
  "eslint-plugin-react": "^7.37.4",
99
101
  "eslint-plugin-react-hooks": "^5.2.0",