@powerhousedao/renown-package 0.0.5 → 0.0.7

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 (23) hide show
  1. package/dist/document-models/renown-credential/gen/document-model.js +35 -7
  2. package/dist/document-models/renown-credential/gen/manager/error.d.ts +11 -1
  3. package/dist/document-models/renown-credential/gen/manager/error.js +26 -12
  4. package/dist/document-models/renown-credential/gen/manager/object.d.ts +1 -1
  5. package/dist/document-models/renown-credential/gen/object.d.ts +1 -1
  6. package/dist/document-models/renown-credential/gen/ph-factories.js +9 -5
  7. package/dist/document-models/renown-credential/gen/reducer.d.ts +1 -1
  8. package/dist/document-models/renown-credential/gen/schema/types.d.ts +12 -13
  9. package/dist/document-models/renown-credential/gen/schema/zod.js +10 -12
  10. package/dist/document-models/renown-credential/gen/utils.d.ts +1 -1
  11. package/dist/document-models/renown-credential/gen/utils.js +11 -5
  12. package/dist/document-models/renown-credential/src/reducers/manager.js +90 -27
  13. package/dist/document-models/renown-user/gen/utils.js +2 -0
  14. package/dist/editors/renown-credential-editor/editor.js +7 -24
  15. package/dist/processors/renown-credential/index.js +35 -22
  16. package/dist/processors/renown-credential/migrations.js +11 -8
  17. package/dist/processors/renown-credential/schema.d.ts +8 -5
  18. package/dist/processors/renown-user/migrations.js +2 -2
  19. package/dist/style.css +13 -0
  20. package/dist/subgraphs/renown-credential/schema.js +13 -13
  21. package/dist/subgraphs/renown-read-model/resolvers.js +5 -2
  22. package/dist/subgraphs/renown-read-model/schema.js +15 -12
  23. package/package.json +3 -1
@@ -27,10 +27,31 @@ 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: "",
31
+ description: "",
32
+ id: "invalid-jwt-payload-error",
33
+ name: "",
34
+ template: "",
35
+ },
36
+ {
37
+ code: "INVALID_JWT_PAYLOAD",
38
+ description: "JWT payload does not contain valid W3C Verifiable Credential fields",
39
+ id: "invalid-jwt-payload-error",
40
+ name: "InvalidJwtPayloadError",
41
+ template: "",
42
+ },
43
+ {
44
+ code: "",
45
+ description: "",
46
+ id: "jwt-verification-error",
47
+ name: "",
48
+ template: "",
49
+ },
50
+ {
51
+ code: "JWT_VERIFICATION_FAILED",
52
+ description: "Failed to verify the JWT signature or the JWT is malformed",
53
+ id: "jwt-verification-error",
54
+ name: "JwtVerificationError",
34
55
  template: "",
35
56
  },
36
57
  {
@@ -40,12 +61,19 @@ export const documentModel = {
40
61
  name: "InvalidClaimsError",
41
62
  template: "",
42
63
  },
64
+ {
65
+ code: "MISSING_TYPE",
66
+ description: "The type field is required and must include VerifiableCredential",
67
+ id: "missing-type-error",
68
+ name: "MissingTypeError",
69
+ template: "",
70
+ },
43
71
  ],
44
72
  examples: [],
45
73
  id: "366dfd44-377f-42d7-949d-a8d82b6a909d",
46
74
  name: "INIT",
47
75
  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}",
76
+ schema: "input InitInput {\n jwt: String!\n}",
49
77
  scope: "global",
50
78
  template: "",
51
79
  },
@@ -130,8 +158,8 @@ export const documentModel = {
130
158
  state: {
131
159
  global: {
132
160
  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}',
161
+ 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 \\"jwtVerificationError\\": null,\\n \\"jwtPayload\\": null,\\n \\"revoked\\": false,\\n \\"revokedAt\\": null,\\n \\"revocationReason\\": null\\n}"',
162
+ schema: 'type CredentialStatus {\n id: String!\n type: String!\n statusPurpose: String!\n statusListIndex: String!\n statusListCredential: String!\n}\n\ntype RenownCredentialState {\n "Complete VC Payload - stores the full verifiable credential object for maximum flexibility"\n vcPayload: String\n \n "W3C VC Common Fields - extracted for 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 "JWT Representation"\n jwt: String\n jwtVerified: Boolean\n jwtVerificationError: String\n jwtPayload: String\n \n "Revocation tracking"\n revoked: Boolean\n revokedAt: DateTime\n revocationReason: String\n}',
135
163
  },
136
164
  local: {
137
165
  examples: [],
@@ -1,4 +1,4 @@
1
- export type ErrorCode = "MissingContextError" | "MissingTypeError" | "InvalidClaimsError" | "AlreadyRevokedError" | "CredentialRevokedError" | "InvalidStatusPurposeError";
1
+ export type ErrorCode = 'MissingContextError' | 'MissingTypeError' | 'InvalidClaimsError' | 'JwtVerificationError' | 'InvalidJwtPayloadError' | 'AlreadyRevokedError' | 'CredentialRevokedError' | 'InvalidStatusPurposeError';
2
2
  export interface ReducerError {
3
3
  errorCode: ErrorCode;
4
4
  }
@@ -14,6 +14,14 @@ export declare class InvalidClaimsError extends Error implements ReducerError {
14
14
  errorCode: ErrorCode;
15
15
  constructor(message?: string);
16
16
  }
17
+ export declare class JwtVerificationError extends Error implements ReducerError {
18
+ errorCode: ErrorCode;
19
+ constructor(message?: string);
20
+ }
21
+ export declare class InvalidJwtPayloadError 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);
@@ -31,6 +39,8 @@ export declare const errors: {
31
39
  MissingContextError: typeof MissingContextError;
32
40
  MissingTypeError: typeof MissingTypeError;
33
41
  InvalidClaimsError: typeof InvalidClaimsError;
42
+ JwtVerificationError: typeof JwtVerificationError;
43
+ InvalidJwtPayloadError: typeof InvalidJwtPayloadError;
34
44
  };
35
45
  Revoke: {
36
46
  AlreadyRevokedError: typeof AlreadyRevokedError;
@@ -1,36 +1,48 @@
1
1
  export class MissingContextError extends Error {
2
- errorCode = "MissingContextError";
3
- constructor(message = "MissingContextError") {
2
+ errorCode = 'MissingContextError';
3
+ constructor(message = 'MissingContextError') {
4
4
  super(message);
5
5
  }
6
6
  }
7
7
  export class MissingTypeError extends Error {
8
- errorCode = "MissingTypeError";
9
- constructor(message = "MissingTypeError") {
8
+ errorCode = 'MissingTypeError';
9
+ constructor(message = 'MissingTypeError') {
10
10
  super(message);
11
11
  }
12
12
  }
13
13
  export class InvalidClaimsError extends Error {
14
- errorCode = "InvalidClaimsError";
15
- constructor(message = "InvalidClaimsError") {
14
+ errorCode = 'InvalidClaimsError';
15
+ constructor(message = 'InvalidClaimsError') {
16
+ super(message);
17
+ }
18
+ }
19
+ export class JwtVerificationError extends Error {
20
+ errorCode = 'JwtVerificationError';
21
+ constructor(message = 'JwtVerificationError') {
22
+ super(message);
23
+ }
24
+ }
25
+ export class InvalidJwtPayloadError extends Error {
26
+ errorCode = 'InvalidJwtPayloadError';
27
+ constructor(message = 'InvalidJwtPayloadError') {
16
28
  super(message);
17
29
  }
18
30
  }
19
31
  export class AlreadyRevokedError extends Error {
20
- errorCode = "AlreadyRevokedError";
21
- constructor(message = "AlreadyRevokedError") {
32
+ errorCode = 'AlreadyRevokedError';
33
+ constructor(message = 'AlreadyRevokedError') {
22
34
  super(message);
23
35
  }
24
36
  }
25
37
  export class CredentialRevokedError extends Error {
26
- errorCode = "CredentialRevokedError";
27
- constructor(message = "CredentialRevokedError") {
38
+ errorCode = 'CredentialRevokedError';
39
+ constructor(message = 'CredentialRevokedError') {
28
40
  super(message);
29
41
  }
30
42
  }
31
43
  export class InvalidStatusPurposeError extends Error {
32
- errorCode = "InvalidStatusPurposeError";
33
- constructor(message = "InvalidStatusPurposeError") {
44
+ errorCode = 'InvalidStatusPurposeError';
45
+ constructor(message = 'InvalidStatusPurposeError') {
34
46
  super(message);
35
47
  }
36
48
  }
@@ -39,6 +51,8 @@ export const errors = {
39
51
  MissingContextError,
40
52
  MissingTypeError,
41
53
  InvalidClaimsError,
54
+ JwtVerificationError,
55
+ InvalidJwtPayloadError,
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,19 @@ 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,
19
+ jwtVerificationError: null,
20
+ jwtPayload: null,
17
21
  revoked: false,
18
22
  revokedAt: null,
19
23
  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,30 @@ 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 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"];
155
+ issuanceDate: Maybe<Scalars["DateTime"]["output"]>;
156
+ issuer: Maybe<Scalars["String"]["output"]>;
163
157
  /** JWT Representation */
164
158
  jwt: Maybe<Scalars["String"]["output"]>;
159
+ jwtPayload: Maybe<Scalars["String"]["output"]>;
160
+ jwtVerificationError: Maybe<Scalars["String"]["output"]>;
161
+ jwtVerified: Maybe<Scalars["Boolean"]["output"]>;
165
162
  revocationReason: Maybe<Scalars["String"]["output"]>;
166
163
  /** Revocation tracking */
167
164
  revoked: Maybe<Scalars["Boolean"]["output"]>;
168
165
  revokedAt: Maybe<Scalars["DateTime"]["output"]>;
169
- type: Array<Scalars["String"]["output"]>;
166
+ type: Maybe<Array<Scalars["String"]["output"]>>;
167
+ /** Complete VC Payload - stores the full verifiable credential object for maximum flexibility */
168
+ vcPayload: Maybe<Scalars["String"]["output"]>;
170
169
  };
171
170
  export type RevokeInput = {
172
171
  reason?: InputMaybe<Scalars["String"]["input"]>;
@@ -15,30 +15,28 @@ 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
+ jwtPayload: z.string().nullable(),
33
+ jwtVerificationError: z.string().nullable(),
34
+ jwtVerified: z.boolean().nullable(),
38
35
  revocationReason: z.string().nullable(),
39
36
  revoked: z.boolean().nullable(),
40
37
  revokedAt: z.string().datetime().nullable(),
41
- type: z.array(z.string()),
38
+ type: z.array(z.string()).nullable(),
39
+ vcPayload: z.string().nullable(),
42
40
  });
43
41
  }
44
42
  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,19 @@
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,
15
+ jwtVerificationError: null,
16
+ jwtPayload: null,
13
17
  revoked: false,
14
18
  revokedAt: null,
15
19
  revocationReason: null,
@@ -30,9 +34,11 @@ export const createDocument = (state) => {
30
34
  return document;
31
35
  };
32
36
  export const saveToFile = (document, path, name) => {
37
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
33
38
  return baseSaveToFile(document, path, "phrc", name);
34
39
  };
35
40
  export const saveToFileHandle = (document, input) => {
41
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
36
42
  return baseSaveToFileHandle(document, input);
37
43
  };
38
44
  export const loadFromFile = (path) => {
@@ -1,36 +1,88 @@
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 metadata
81
+ state.jwt = action.input.jwt;
82
+ state.jwtVerified = true;
83
+ state.jwtVerificationError = null;
84
+ state.jwtPayload = JSON.stringify(payload);
85
+ // Initialize revocation tracking
34
86
  state.revoked = false;
35
87
  state.revokedAt = null;
36
88
  state.revocationReason = null;
@@ -47,6 +99,17 @@ export const reducer = {
47
99
  throw new InvalidClaimsError("Credential subject must be valid JSON");
48
100
  }
49
101
  state.credentialSubject = action.input.credentialSubject;
102
+ // Update vcPayload if it exists
103
+ if (state.vcPayload) {
104
+ try {
105
+ const vc = JSON.parse(state.vcPayload);
106
+ vc.credentialSubject = JSON.parse(action.input.credentialSubject);
107
+ state.vcPayload = JSON.stringify(vc);
108
+ }
109
+ catch (e) {
110
+ // If vcPayload can't be updated, just continue
111
+ }
112
+ }
50
113
  // Clear JWT as credential content has changed
51
114
  state.jwt = null;
52
115
  },
@@ -21,9 +21,11 @@ export const createDocument = (state) => {
21
21
  return document;
22
22
  };
23
23
  export const saveToFile = (document, path, name) => {
24
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
24
25
  return baseSaveToFile(document, path, "phru", name);
25
26
  };
26
27
  export const saveToFileHandle = (document, input) => {
28
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
27
29
  return baseSaveToFileHandle(document, input);
28
30
  };
29
31
  export const loadFromFile = (path) => {
@@ -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, jwtPayload, 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 ? (_jsxs(_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 }) }), jwtPayload && (_jsxs("div", { className: "mt-4", children: [_jsx("label", { className: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2", children: "Decoded JWT Payload" }), _jsx("pre", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200 overflow-auto text-xs max-h-64", children: JSON.stringify(JSON.parse(jwtPayload), null, 2) })] }))] })) : (_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,38 @@ 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
+ vc_payload: state.vcPayload || null,
40
+ context: state.context ? JSON.stringify(state.context) : null,
41
+ credential_id: state.id || null,
42
+ type: state.type ? JSON.stringify(state.type) : null,
43
+ issuer: state.issuer || null,
44
+ issuance_date: state.issuanceDate
45
+ ? new Date(state.issuanceDate)
46
+ : null,
47
+ credential_subject: state.credentialSubject || null,
48
+ expiration_date: state.expirationDate
49
+ ? new Date(state.expirationDate)
44
50
  : 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,
51
+ credential_status_id: state.credentialStatus?.id || null,
52
+ credential_status_type: state.credentialStatus?.type || null,
53
+ credential_status_purpose: state.credentialStatus?.statusPurpose || null,
54
+ credential_status_list_index: state.credentialStatus?.statusListIndex || null,
55
+ credential_status_list_credential: state.credentialStatus?.statusListCredential || null,
56
+ jwt: state.jwt || null,
57
+ jwt_payload: state.jwtPayload || null,
58
+ jwt_verified: state.jwtVerified || false,
59
+ revoked: state.revoked || false,
60
+ revoked_at: state.revokedAt ? new Date(state.revokedAt) : null,
61
+ revocation_reason: state.revocationReason || null,
54
62
  created_at: new Date(),
55
63
  updated_at: new Date(),
56
64
  })
@@ -59,13 +67,18 @@ export class RenownCredentialProcessor extends RelationalDbProcessor {
59
67
  break;
60
68
  }
61
69
  case "UPDATE_CREDENTIAL_SUBJECT": {
62
- const input = operation.action.input;
63
- if (input && existingCredential) {
70
+ // Access the updated state to get the synced vcPayload
71
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
72
+ const state = (strand.state)?.global;
73
+ if (state && existingCredential) {
64
74
  await this.relationalDb
65
75
  .updateTable("renown_credential")
66
76
  .set({
67
- credential_subject: input.credentialSubject,
77
+ credential_subject: state.credentialSubject || null,
78
+ vc_payload: state.vcPayload || null, // Sync vcPayload with updated credentialSubject
68
79
  jwt: null, // Clear JWT when content changes
80
+ jwt_payload: null, // Also clear JWT payload
81
+ jwt_verified: false, // Mark as unverified since content changed
69
82
  updated_at: new Date(),
70
83
  })
71
84
  .where("document_id", "=", documentId)
@@ -1,15 +1,16 @@
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("vc_payload", "text") // Complete VC JSON object
8
+ .addColumn("context", "text") // JSON array - extracted for convenience
8
9
  .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
10
+ .addColumn("type", "text") // JSON array - extracted for convenience
11
+ .addColumn("issuer", "varchar(255)") // Now nullable to support any VC structure
12
+ .addColumn("issuance_date", "timestamp") // Now nullable
13
+ .addColumn("credential_subject", "text") // JSON object - now nullable
13
14
  .addColumn("expiration_date", "timestamp")
14
15
  .addColumn("credential_status_id", "varchar(255)")
15
16
  .addColumn("credential_status_type", "varchar(255)")
@@ -17,6 +18,8 @@ export async function up(db) {
17
18
  .addColumn("credential_status_list_index", "varchar(255)")
18
19
  .addColumn("credential_status_list_credential", "text")
19
20
  .addColumn("jwt", "text")
21
+ .addColumn("jwt_payload", "text") // Complete JWT payload JSON object
22
+ .addColumn("jwt_verified", "boolean", (col) => col.notNull().defaultTo(false))
20
23
  .addColumn("revoked", "boolean", (col) => col.notNull().defaultTo(false))
21
24
  .addColumn("revoked_at", "timestamp")
22
25
  .addColumn("revocation_reason", "text")
@@ -72,6 +75,6 @@ export async function down(db) {
72
75
  .dropIndex("idx_renown_credential_credential_id")
73
76
  .ifExists()
74
77
  .execute();
75
- // Drop renown_credential table
76
- await db.schema.dropTable("renown_credential").ifExists().execute();
78
+ // Drop renown_credential table with CASCADE to drop dependent objects
79
+ await db.schema.dropTable("renown_credential").ifExists().cascade().execute();
77
80
  }
@@ -3,12 +3,13 @@ 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
+ vc_payload: string | null;
7
+ context: string | null;
7
8
  credential_id: string | null;
8
- type: string;
9
- issuer: string;
10
- issuance_date: Timestamp;
11
- credential_subject: string;
9
+ type: string | null;
10
+ issuer: string | null;
11
+ issuance_date: Timestamp | null;
12
+ credential_subject: string | null;
12
13
  expiration_date: Timestamp | null;
13
14
  credential_status_id: string | null;
14
15
  credential_status_type: string | null;
@@ -16,6 +17,8 @@ export interface RenownCredential {
16
17
  credential_status_list_index: string | null;
17
18
  credential_status_list_credential: string | null;
18
19
  jwt: string | null;
20
+ jwt_payload: string | null;
21
+ jwt_verified: boolean;
19
22
  revoked: boolean;
20
23
  revoked_at: Timestamp | null;
21
24
  revocation_reason: string | null;
@@ -31,6 +31,6 @@ export async function down(db) {
31
31
  // Drop renown_user indexes
32
32
  await db.schema.dropIndex("idx_renown_user_eth_address").ifExists().execute();
33
33
  await db.schema.dropIndex("idx_renown_user_username").ifExists().execute();
34
- // Drop renown_user table
35
- await db.schema.dropTable("renown_user").ifExists().execute();
34
+ // Drop renown_user table with CASCADE to drop dependent objects
35
+ await db.schema.dropTable("renown_user").ifExists().cascade().execute();
36
36
  }
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);
@@ -313,6 +314,9 @@
313
314
  .mt-2 {
314
315
  margin-top: calc(var(--spacing) * 2);
315
316
  }
317
+ .mt-4 {
318
+ margin-top: calc(var(--spacing) * 4);
319
+ }
316
320
  .mt-6 {
317
321
  margin-top: calc(var(--spacing) * 6);
318
322
  }
@@ -361,6 +365,12 @@
361
365
  .h-24 {
362
366
  height: calc(var(--spacing) * 24);
363
367
  }
368
+ .max-h-64 {
369
+ max-height: calc(var(--spacing) * 64);
370
+ }
371
+ .max-h-96 {
372
+ max-height: calc(var(--spacing) * 96);
373
+ }
364
374
  .min-h-screen {
365
375
  min-height: 100vh;
366
376
  }
@@ -526,6 +536,9 @@
526
536
  .bg-green-100 {
527
537
  background-color: var(--color-green-100);
528
538
  }
539
+ .bg-purple-50 {
540
+ background-color: var(--color-purple-50);
541
+ }
529
542
  .bg-red-50 {
530
543
  background-color: var(--color-red-50);
531
544
  }
@@ -12,13 +12,16 @@ export const schema = gql `
12
12
  }
13
13
 
14
14
  type RenownCredentialState {
15
- "W3C VC Required Fields"
16
- context: [String!]!
15
+ "Complete VC Payload - stores the full verifiable credential object for maximum flexibility"
16
+ vcPayload: String
17
+
18
+ "W3C VC Common Fields - extracted for convenience, may be null for non-standard VCs"
19
+ context: [String!]
17
20
  id: String
18
- type: [String!]!
19
- issuer: String!
20
- issuanceDate: DateTime!
21
- credentialSubject: String!
21
+ type: [String!]
22
+ issuer: String
23
+ issuanceDate: DateTime
24
+ credentialSubject: String
22
25
 
23
26
  "W3C VC Optional Fields"
24
27
  expirationDate: DateTime
@@ -26,6 +29,9 @@ export const schema = gql `
26
29
 
27
30
  "JWT Representation"
28
31
  jwt: String
32
+ jwtVerified: Boolean
33
+ jwtVerificationError: String
34
+ jwtPayload: String
29
35
 
30
36
  "Revocation tracking"
31
37
  revoked: Boolean
@@ -82,13 +88,7 @@ export const schema = gql `
82
88
  Module: Manager
83
89
  """
84
90
  input RenownCredential_InitInput {
85
- context: [String!]
86
- id: String
87
- type: [String!]
88
- issuer: String!
89
- issuanceDate: DateTime!
90
- credentialSubject: String!
91
- expirationDate: DateTime
91
+ jwt: String!
92
92
  }
93
93
  input RenownCredential_RevokeInput {
94
94
  revokedAt: DateTime!
@@ -10,9 +10,10 @@ const mapToUser = (user) => ({
10
10
  });
11
11
  const mapToCredential = (credential) => ({
12
12
  documentId: credential.document_id,
13
+ vcPayload: credential.vc_payload,
13
14
  credentialId: credential.credential_id,
14
- context: JSON.parse(credential.context),
15
- type: JSON.parse(credential.type),
15
+ context: credential.context ? JSON.parse(credential.context) : null,
16
+ type: credential.type ? JSON.parse(credential.type) : null,
16
17
  issuer: credential.issuer,
17
18
  issuanceDate: credential.issuance_date,
18
19
  credentialSubject: credential.credential_subject,
@@ -31,6 +32,8 @@ const mapToCredential = (credential) => ({
31
32
  }
32
33
  : null,
33
34
  jwt: credential.jwt,
35
+ jwtPayload: credential.jwt_payload,
36
+ jwtVerified: credential.jwt_verified,
34
37
  revoked: credential.revoked,
35
38
  revokedAt: credential.revoked_at,
36
39
  revocationReason: credential.revocation_reason,
@@ -3,7 +3,7 @@ export const schema = gql `
3
3
  """
4
4
  Subgraph definition for Renown Read Model
5
5
  """
6
- type RenownUser {
6
+ type ReadRenownUser {
7
7
  documentId: String!
8
8
  username: String
9
9
  ethAddress: String
@@ -26,17 +26,20 @@ export const schema = gql `
26
26
  usernames: [String!]
27
27
  }
28
28
 
29
- type RenownCredential {
29
+ type ReadRenownCredential {
30
30
  documentId: String!
31
+ vcPayload: String
31
32
  credentialId: String
32
- context: [String!]!
33
- type: [String!]!
34
- issuer: String!
35
- issuanceDate: DateTime!
36
- credentialSubject: String!
33
+ context: [String!]
34
+ type: [String!]
35
+ issuer: String
36
+ issuanceDate: DateTime
37
+ credentialSubject: String
37
38
  expirationDate: DateTime
38
- credentialStatus: CredentialStatus
39
+ credentialStatus: ReadCredentialStatus
39
40
  jwt: String
41
+ jwtPayload: String
42
+ jwtVerified: Boolean!
40
43
  revoked: Boolean!
41
44
  revokedAt: DateTime
42
45
  revocationReason: String
@@ -44,7 +47,7 @@ export const schema = gql `
44
47
  updatedAt: DateTime
45
48
  }
46
49
 
47
- type CredentialStatus {
50
+ type ReadCredentialStatus {
48
51
  id: String!
49
52
  type: String!
50
53
  statusPurpose: String!
@@ -61,8 +64,8 @@ export const schema = gql `
61
64
  }
62
65
 
63
66
  type Query {
64
- renownUser(input: RenownUserInput!): RenownUser
65
- renownUsers(input: RenownUsersInput!): [RenownUser!]!
66
- renownCredentials(input: RenownCredentialsInput!): [RenownCredential!]!
67
+ renownUser(input: RenownUserInput!): ReadRenownUser
68
+ renownUsers(input: RenownUsersInput!): [ReadRenownUser!]!
69
+ renownCredentials(input: RenownCredentialsInput!): [ReadRenownCredential!]!
67
70
  }
68
71
  `;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powerhousedao/renown-package",
3
3
  "description": "",
4
- "version": "0.0.5",
4
+ "version": "0.0.7",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",
7
7
  "files": [
@@ -67,6 +67,8 @@
67
67
  "@powerhousedao/design-system": "staging",
68
68
  "@powerhousedao/document-engineering": "^1.37.0",
69
69
  "@powerhousedao/vetra": "staging",
70
+ "did-jwt": "^8.0.18",
71
+ "did-jwt-vc": "^4.0.16",
70
72
  "document-model": "staging",
71
73
  "graphql": "^16.10.0",
72
74
  "graphql-tag": "^2.12.6",