@1sat/permission-module 0.0.50 → 0.0.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/apply.d.ts +1 -1
  2. package/dist/apply.d.ts.map +1 -1
  3. package/dist/apply.js +3 -3
  4. package/dist/apply.js.map +1 -1
  5. package/dist/apply.test.js +48 -43
  6. package/dist/apply.test.js.map +1 -1
  7. package/dist/basketAccess.d.ts +40 -0
  8. package/dist/basketAccess.d.ts.map +1 -0
  9. package/dist/basketAccess.js +238 -0
  10. package/dist/basketAccess.js.map +1 -0
  11. package/dist/buildPromptIntent.d.ts +15 -0
  12. package/dist/buildPromptIntent.d.ts.map +1 -0
  13. package/dist/buildPromptIntent.js +575 -0
  14. package/dist/buildPromptIntent.js.map +1 -0
  15. package/dist/createOneSatPermissionModule.d.ts +10 -5
  16. package/dist/createOneSatPermissionModule.d.ts.map +1 -1
  17. package/dist/createOneSatPermissionModule.js +28 -6
  18. package/dist/createOneSatPermissionModule.js.map +1 -1
  19. package/dist/enrichIntent.d.ts +121 -5
  20. package/dist/enrichIntent.d.ts.map +1 -1
  21. package/dist/enrichIntent.js +576 -137
  22. package/dist/enrichIntent.js.map +1 -1
  23. package/dist/handlers.d.ts +12 -32
  24. package/dist/handlers.d.ts.map +1 -1
  25. package/dist/handlers.js +121 -155
  26. package/dist/handlers.js.map +1 -1
  27. package/dist/index.d.ts +5 -2
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +4 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/listOutputsScope.test.d.ts +2 -0
  32. package/dist/listOutputsScope.test.d.ts.map +1 -0
  33. package/dist/listOutputsScope.test.js +126 -0
  34. package/dist/listOutputsScope.test.js.map +1 -0
  35. package/dist/promptModel.d.ts +115 -0
  36. package/dist/promptModel.d.ts.map +1 -0
  37. package/dist/promptModel.js +7 -0
  38. package/dist/promptModel.js.map +1 -0
  39. package/dist/types.d.ts +36 -10
  40. package/dist/types.d.ts.map +1 -1
  41. package/dist/types.js.map +1 -1
  42. package/dist/verifyIntent.d.ts +4 -4
  43. package/dist/verifyIntent.d.ts.map +1 -1
  44. package/dist/verifyIntent.js +120 -40
  45. package/dist/verifyIntent.js.map +1 -1
  46. package/dist/viewScope.d.ts +51 -0
  47. package/dist/viewScope.d.ts.map +1 -0
  48. package/dist/viewScope.js +113 -0
  49. package/dist/viewScope.js.map +1 -0
  50. package/dist/viewScope.test.d.ts +2 -0
  51. package/dist/viewScope.test.d.ts.map +1 -0
  52. package/dist/viewScope.test.js +60 -0
  53. package/dist/viewScope.test.js.map +1 -0
  54. package/package.json +42 -42
@@ -0,0 +1,126 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { handleListOutputsRequest } from './basketAccess';
3
+ import { CommitmentCache } from './commitmentCache';
4
+ function mockStore() {
5
+ const map = new Map();
6
+ const keyOf = (k) => `${k.type}|${k.originator}|${k.basket ?? ''}`;
7
+ return {
8
+ async findGrant(key) {
9
+ const g = map.get(keyOf(key));
10
+ return g
11
+ ? {
12
+ key,
13
+ expiry: g.expiry,
14
+ grantedAt: 0,
15
+ }
16
+ : null;
17
+ },
18
+ async putGrant(grant) {
19
+ map.set(keyOf(grant.key), { expiry: grant.expiry });
20
+ },
21
+ };
22
+ }
23
+ function deps(opts) {
24
+ return {
25
+ wallet: {},
26
+ promptHandler: opts.promptHandler ?? (async () => true),
27
+ cache: new CommitmentCache(60),
28
+ schemeId: '1sat',
29
+ ownedBaskets: new Set(['1sat']),
30
+ adminOriginator: opts.adminOriginator,
31
+ permissionStore: opts.permissionStore,
32
+ };
33
+ }
34
+ const COLL = 'collection:a1b2c3d4e5f6070890abcdef1234567890abcdef1234567890abcdef12345678_0';
35
+ describe('handleListOutputsRequest scopes', () => {
36
+ test('rejects bare p 1sat', async () => {
37
+ await expect(handleListOutputsRequest(deps({}), { basket: 'p 1sat' }, 'app.example')).rejects.toThrow(/requires a scope/);
38
+ });
39
+ test('rejects collection scope without axis tag', async () => {
40
+ await expect(handleListOutputsRequest(deps({}), { basket: 'p 1sat collection' }, 'app.example')).rejects.toThrow(/requires at least one collection:/);
41
+ });
42
+ test('normalizes collection scope; keeps tags; forces all', async () => {
43
+ const next = await handleListOutputsRequest(deps({ promptHandler: async () => true }), {
44
+ basket: 'p 1sat collection',
45
+ tags: [COLL, 'type:image/png'],
46
+ tagQueryMode: 'any',
47
+ }, 'app.example');
48
+ expect(next.basket).toBe('1sat');
49
+ expect(next.tags).toEqual([COLL, 'type:image/png']);
50
+ expect(next.tagQueryMode).toBe('all');
51
+ });
52
+ test('p 1sat all does not require axis tags', async () => {
53
+ const next = await handleListOutputsRequest(deps({ promptHandler: async () => true }), {
54
+ basket: 'p 1sat all',
55
+ tags: ['type:image/png'],
56
+ tagQueryMode: 'any',
57
+ }, 'app.example');
58
+ expect(next.basket).toBe('1sat');
59
+ expect(next.tags).toEqual(['type:image/png']);
60
+ expect(next.tagQueryMode).toBe('any');
61
+ });
62
+ test('admin skips prompt', async () => {
63
+ let prompted = false;
64
+ await handleListOutputsRequest(deps({
65
+ adminOriginator: 'admin.local',
66
+ promptHandler: async () => {
67
+ prompted = true;
68
+ return true;
69
+ },
70
+ }), { basket: 'p 1sat all' }, 'admin.local');
71
+ expect(prompted).toBe(false);
72
+ });
73
+ test('p 1sat id auto-allows without view grant prompt', async () => {
74
+ let prompted = false;
75
+ const next = await handleListOutputsRequest(deps({
76
+ promptHandler: async () => {
77
+ prompted = true;
78
+ return true;
79
+ },
80
+ }), {
81
+ basket: 'p 1sat id',
82
+ tags: ['id:abc123'],
83
+ }, 'app.example');
84
+ expect(prompted).toBe(false);
85
+ expect(next.basket).toBe('1sat');
86
+ expect(next.tags).toEqual(['id:abc123']);
87
+ expect(next.tagQueryMode).toBeUndefined();
88
+ });
89
+ test('p 1sat id leaves caller tagQueryMode', async () => {
90
+ const next = await handleListOutputsRequest(deps({ promptHandler: async () => true }), {
91
+ basket: 'p 1sat id',
92
+ tags: ['id:abc123', 'id:def456'],
93
+ tagQueryMode: 'any',
94
+ }, 'id-any.example');
95
+ expect(next.basket).toBe('1sat');
96
+ expect(next.tags).toEqual(['id:abc123', 'id:def456']);
97
+ expect(next.tagQueryMode).toBe('any');
98
+ });
99
+ test('p 1sat id requires id: tag', async () => {
100
+ await expect(handleListOutputsRequest(deps({}), { basket: 'p 1sat id' }, 'app.example')).rejects.toThrow(/requires at least one id:/);
101
+ });
102
+ test('collection grant is per tag value', async () => {
103
+ const prompts = [];
104
+ const d = deps({
105
+ permissionStore: mockStore(),
106
+ promptHandler: async (req) => {
107
+ if (req.kind === 'basketAccess') {
108
+ const baskets = req.payload.baskets;
109
+ prompts.push(baskets.map((b) => b.basket));
110
+ }
111
+ return true;
112
+ },
113
+ });
114
+ const collB = 'collection:b1b2c3d4e5f6070890abcdef1234567890abcdef1234567890abcdef12345678_0';
115
+ await handleListOutputsRequest(d, { basket: 'p 1sat collection', tags: [COLL] }, 'app.example');
116
+ expect(prompts).toHaveLength(1);
117
+ expect(prompts[0][0]).toContain('a1b2c3d4');
118
+ prompts.length = 0;
119
+ await handleListOutputsRequest(d, { basket: 'p 1sat collection', tags: [COLL] }, 'app.example');
120
+ expect(prompts).toHaveLength(0);
121
+ await handleListOutputsRequest(d, { basket: 'p 1sat collection', tags: [collB] }, 'app.example');
122
+ expect(prompts).toHaveLength(1);
123
+ expect(prompts[0][0]).toContain('b1b2c3d4');
124
+ });
125
+ });
126
+ //# sourceMappingURL=listOutputsScope.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listOutputsScope.test.js","sourceRoot":"","sources":["../src/listOutputsScope.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ import type { TrustState } from './enrichIntent';
2
+ /**
3
+ * Serializable prompt IR.
4
+ *
5
+ * Built once in the permission module after parse/enrich. The UI only renders
6
+ * these fields — it does not re-classify scripts, tags, or baskets.
7
+ */
8
+ export type PreviewKind = 'image' | 'text' | 'json' | 'html' | 'svg' | 'opns' | 'none';
9
+ export type PanelVariant = 'ordinal' | 'token' | 'value';
10
+ /** Visual tone — burn panels use danger. */
11
+ export type PanelTone = 'default' | 'danger';
12
+ export type ValueIcon = 'lock' | 'unlock' | 'pay';
13
+ /** One labeled detail line under a panel title. */
14
+ export interface PromptDetailRow {
15
+ key: string;
16
+ /** Display value (may be shortened for addresses/origins). */
17
+ value: string;
18
+ /** Full string for clipboard when shortened. */
19
+ copyValue?: string;
20
+ }
21
+ /**
22
+ * One self-contained card block (ordinal edge, lock/pay, token, …).
23
+ * Media and action copy are settled before this crosses the wire.
24
+ */
25
+ export interface PromptPanel {
26
+ title: string;
27
+ subtitle?: string;
28
+ subtitleCopy?: string;
29
+ meta?: PromptDetailRow[];
30
+ variant?: PanelVariant;
31
+ previewKind?: PreviewKind;
32
+ /** Image / avatar URL when preview is image or opns avatar. */
33
+ imageUrl?: string;
34
+ /** Fetch URL for text/json/html/svg previews. */
35
+ contentUrl?: string;
36
+ /** Inline body when the script was decoded (mint / no OrdFS URL yet). */
37
+ previewText?: string;
38
+ /** Full sat amount for value panels — never truncated in the UI. */
39
+ amountSats?: number;
40
+ valueIcon?: ValueIcon;
41
+ /** OpNS profile name shown as hero text when previewKind is opns. */
42
+ opnsHero?: string;
43
+ /** Burn / destructive ops — subtle danger chrome. */
44
+ tone?: PanelTone;
45
+ }
46
+ /**
47
+ * Reserved for admin pre-fund (BRC-29 payment UTXOs applied before prompt).
48
+ * Omit until pre-fund lands — structure is here so panels are not ordinal-only.
49
+ */
50
+ export interface PromptFunding {
51
+ networkFeeSats?: number;
52
+ fundingInputSats?: number;
53
+ changeSats?: number;
54
+ note?: string;
55
+ }
56
+ /** Overlay/indexer fee (not miner fee). */
57
+ export interface PromptIndexerFee {
58
+ sats: number;
59
+ note?: string;
60
+ }
61
+ export interface PromptTrust {
62
+ state: TrustState;
63
+ note?: string;
64
+ }
65
+ /**
66
+ * Facts verifyIntent needs without the UI re-deriving them from tags.
67
+ * Optional — only purchases/hint paths set trust + verify.
68
+ */
69
+ export interface PromptVerifyContext {
70
+ kind: string;
71
+ inputs: Array<{
72
+ basket: string;
73
+ id: string;
74
+ outpoint: string;
75
+ satoshis: number;
76
+ tags: string[];
77
+ /** Case-preserving fields (sym, name) — tags are lowercased by BRC-100. */
78
+ customInstructions?: string;
79
+ }>;
80
+ outputs: Array<{
81
+ index: number;
82
+ satoshis: number;
83
+ basket?: string;
84
+ tags: string[];
85
+ recipient?: string;
86
+ listingPriceSats?: number;
87
+ }>;
88
+ contentUrls?: Record<string, string>;
89
+ }
90
+ /**
91
+ * Transaction prompt payload (`PromptRequest.kind === 'transaction'`).
92
+ * Pure data — no functions, safe across process boundaries.
93
+ */
94
+ /**
95
+ * Serializable transaction approval view: title, panels, fees.
96
+ * Not a classification taxonomy — pure display IR from one parse.
97
+ */
98
+ export interface TransactionPrompt {
99
+ /** Header title — currently always "Transaction Request". */
100
+ title: string;
101
+ /** Header subtitle — originator line. */
102
+ subtitle: string;
103
+ /** Primary body: one panel per op (ordinal edge, lock, pay, …). */
104
+ panels: PromptPanel[];
105
+ /** Secondary lines that are not full panels (leftover seals, etc.). */
106
+ rows: PromptDetailRow[];
107
+ trust?: PromptTrust;
108
+ indexerFee?: PromptIndexerFee;
109
+ /** Present after pre-fund; reserved until then. */
110
+ funding?: PromptFunding;
111
+ /** Purchase verification context for the host UI. */
112
+ verify?: PromptVerifyContext;
113
+ }
114
+ export declare function isTransactionPrompt(value: unknown): value is TransactionPrompt;
115
+ //# sourceMappingURL=promptModel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promptModel.d.ts","sourceRoot":"","sources":["../src/promptModel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export function isTransactionPrompt(value) {
2
+ if (!value || typeof value !== 'object')
3
+ return false;
4
+ const o = value;
5
+ return Array.isArray(o.panels) && typeof o.title === 'string';
6
+ }
7
+ //# sourceMappingURL=promptModel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promptModel.js","sourceRoot":"","sources":["../src/promptModel.ts"],"names":[],"mappings":"AAqIA,MAAM,UAAU,mBAAmB,CAClC,KAAc;IAEd,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IACrD,MAAM,CAAC,GAAG,KAAgC,CAAA;IAC1C,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAA;AAC9D,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { PermissionSchemeId } from '@1sat/types';
1
2
  import type { IPermissionStore } from '@1sat/wallet';
2
3
  import type { WalletInterface } from '@bsv/sdk';
3
4
  /**
@@ -33,17 +34,13 @@ export interface PromptRequest {
33
34
  kind: PromptKind;
34
35
  originator: string;
35
36
  /**
36
- * Context payload for the host UI.
37
+ * Host UI data.
37
38
  *
38
- * Transaction kind (typical fields the UI consumes):
39
- * - `p1satIntent`e.g. `opns.register`, `ordinal.transfer`
40
- * - `inputs` / `outputs` / `contentUrls` — assets, recipients, ORDFS/icon URLs
41
- * - `trust?` — `{ state: 'verified'|'unverified'|'mismatch', note? }` purchases
42
- * - `indexerFeeSats?` / `indexerFeeNote?` — overlay fee (not miner/DSAP)
43
- *
44
- * For `kind: 'basketAccess'`: `{ baskets: BasketAccessRequest[] }`.
39
+ * Transaction: {@link import('./promptModel').TransactionPrompt}
40
+ * (panels already built UI only renders).
41
+ * basketAccess: `{ baskets: BasketAccessRequest[] }`.
45
42
  */
46
- intent: Record<string, unknown>;
43
+ payload: Record<string, unknown>;
47
44
  /** Short human-readable summary line. Filled in by the module. */
48
45
  summary: string;
49
46
  }
@@ -52,8 +49,17 @@ export interface PromptRequest {
52
49
  * `kind: 'basketAccess'` prompt intent.
53
50
  */
54
51
  export interface BasketAccessRequest {
52
+ /** Grant key (e.g. `p 1sat collection <id>` or plain `1sat`). */
55
53
  basket: string;
56
54
  description?: string;
55
+ /** View axis when this is a scoped grant (`collection` / `app` / `creator` / `all`). */
56
+ scope?: string;
57
+ /** Axis filter value (e.g. collection outpoint). Always show when set. */
58
+ value?: string;
59
+ /** Optional display name (e.g. OrdFS MAP name for a collection). */
60
+ name?: string;
61
+ /** Optional preview image URL (OrdFS content). */
62
+ imageUrl?: string;
57
63
  }
58
64
  /**
59
65
  * Callback the host wallet provides for showing prompts and awaiting
@@ -93,14 +99,24 @@ export interface VerificationServices {
93
99
  token?: {
94
100
  sym?: string;
95
101
  dec?: string | number;
102
+ icon?: string;
96
103
  };
97
104
  status?: {
98
105
  is_active?: boolean;
99
106
  };
100
107
  } | null>;
108
+ /**
109
+ * Validate outpoints against the token overlay topic.
110
+ * Returns only those found (optionally unspent).
111
+ */
112
+ validateOutputs?(tokenId: string, outpoints: string[], opts?: {
113
+ unspent?: boolean;
114
+ }): Promise<Array<{
115
+ outpoint: string;
116
+ }>>;
101
117
  };
102
118
  }
103
- /** Args accepted by `createOneSatPermissionModule`. */
119
+ /** Args accepted by `createOneSatPermissionModule` / scheme modules. */
104
120
  export interface CreateOneSatPermissionModuleArgs {
105
121
  /**
106
122
  * The underlying wallet (NOT the WalletPermissionsManager wrapper).
@@ -110,6 +126,16 @@ export interface CreateOneSatPermissionModuleArgs {
110
126
  wallet: WalletInterface;
111
127
  /** UI callback for prompting the user. */
112
128
  promptHandler: PromptHandler;
129
+ /**
130
+ * BRC-99 scheme id this module instance handles (e.g. `1sat`, `opns`, `bsv21`).
131
+ * Default `1sat`.
132
+ */
133
+ schemeId?: PermissionSchemeId;
134
+ /**
135
+ * Storage baskets this module may gate on list/internalize.
136
+ * Default: `[schemeId]` (scheme id === basket name).
137
+ */
138
+ baskets?: readonly string[];
113
139
  /**
114
140
  * Optional persistent grant store consulted before prompting for
115
141
  * basket-access on P-baskets. Same `IPermissionStore` instance the
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE/C;;;;;;;GAOG;AACH,eAAO,MAAM,8BAA8B,KAAK,CAAA;AAEhD,iEAAiE;AACjE,MAAM,WAAW,kBAAkB;IAClC,uEAAuE;IACvE,WAAW,EAAE,MAAM,CAAA;IACnB,+DAA+D;IAC/D,mBAAmB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAChC,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAA;IAClB,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAA;CACjB;AAED,gEAAgE;AAChE,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,CAAA;AAElF;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC7B,IAAI,EAAE,UAAU,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB;;;;;;;;;;OAUG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAExE;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAoB;IACpC,KAAK,CAAC,EAAE;QACP,YAAY,CAAC,CACZ,SAAS,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE;YAAE,WAAW,CAAC,EAAE,MAAM,CAAC;YAAC,aAAa,CAAC,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAC;YAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;SAAE,GAAG,IAAI,CAAC,CAAC,CAAA;QACnI;;;WAGG;QACH,aAAa,CAAC,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KACxC,CAAA;IACD,IAAI,CAAC,EAAE;QACN,SAAS,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC,CAAA;KAC5E,CAAA;IACD,KAAK,CAAC,EAAE;QACP,eAAe,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;YAC1C,KAAK,CAAC,EAAE;gBAAE,GAAG,CAAC,EAAE,MAAM,CAAC;gBAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;aAAE,CAAA;YAC/C,MAAM,CAAC,EAAE;gBAAE,SAAS,CAAC,EAAE,OAAO,CAAA;aAAE,CAAA;SAChC,GAAG,IAAI,CAAC,CAAA;KACT,CAAA;CACD;AAED,uDAAuD;AACvD,MAAM,WAAW,gCAAgC;IAChD;;;;OAIG;IACH,MAAM,EAAE,eAAe,CAAA;IACvB,0CAA0C;IAC1C,aAAa,EAAE,aAAa,CAAA;IAC5B;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,gBAAgB,CAAA;IAClC;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,oBAAoB,CAAA;IAC/B,4DAA4D;IAC5D,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;CACxB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,EAAE,CAAA"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,EAAE,CAAA"}
@@ -8,8 +8,6 @@ export interface VerificationResult {
8
8
  note?: string;
9
9
  /** Content type confirmed by ORDFS, when it answered. */
10
10
  contentType?: string;
11
- /** Content length in bytes confirmed by ORDFS, when it answered. */
12
- contentLength?: number;
13
11
  /**
14
12
  * True origin as resolved by ORDFS.
15
13
  *
@@ -24,10 +22,12 @@ export interface VerificationResult {
24
22
  contentUrl?: string;
25
23
  }
26
24
  /**
27
- * Verify the assets on a purchase intent.
25
+ * Verify assets on a purchase or BSV21 transfer.
28
26
  *
29
27
  * Returns `unverified` for anything we cannot positively confirm, including
30
28
  * when no services are wired at all. Never throws.
31
29
  */
32
- export declare function verifyIntent(services: VerificationServices | undefined, p1satIntent: string | undefined, inputs: EnrichedAsset[], outputs: EnrichedOutput[], contentUrlForOrigin?: (origin: string) => string): Promise<VerificationResult>;
30
+ export declare function verifyIntent(services: VerificationServices | undefined,
31
+ /** Prompt kind from script/heuristic classify, or legacy intent id. */
32
+ kindOrIntent: string | undefined, inputs: EnrichedAsset[], outputs: EnrichedOutput[], contentUrlForOrigin?: (origin: string) => string): Promise<VerificationResult>;
33
33
  //# sourceMappingURL=verifyIntent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"verifyIntent.d.ts","sourceRoot":"","sources":["../src/verifyIntent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC/E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAEnD,+EAA+E;AAC/E,eAAO,MAAM,uBAAuB,OAAO,CAAA;AAE3C,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,UAAU,CAAA;IACjB,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAA;CACnB;AA8HD;;;;;GAKG;AACH,wBAAsB,YAAY,CACjC,QAAQ,EAAE,oBAAoB,GAAG,SAAS,EAC1C,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,MAAM,EAAE,aAAa,EAAE,EACvB,OAAO,EAAE,cAAc,EAAE,EACzB,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC9C,OAAO,CAAC,kBAAkB,CAAC,CA+C7B"}
1
+ {"version":3,"file":"verifyIntent.d.ts","sourceRoot":"","sources":["../src/verifyIntent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC/E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAEnD,+EAA+E;AAC/E,eAAO,MAAM,uBAAuB,OAAO,CAAA;AAE3C,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,UAAU,CAAA;IACjB,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAA;CACnB;AAyKD;;;;;GAKG;AACH,wBAAsB,YAAY,CACjC,QAAQ,EAAE,oBAAoB,GAAG,SAAS;AAC1C,uEAAuE;AACvE,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,MAAM,EAAE,aAAa,EAAE,EACvB,OAAO,EAAE,cAAc,EAAE,EACzB,mBAAmB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAC9C,OAAO,CAAC,kBAAkB,CAAC,CA4G7B"}
@@ -1,3 +1,4 @@
1
+ import { formatOrdinalOutpoint } from '@1sat/types';
1
2
  /** How long any single verification lookup may take before it is abandoned. */
2
3
  export const VERIFICATION_TIMEOUT_MS = 2000;
3
4
  /**
@@ -36,21 +37,21 @@ async function verifyOrdinal(services, origin, claimedTypes = []) {
36
37
  const ordfs = services.ordfs;
37
38
  if (typeof ordfs?.bulkMetadata !== 'function')
38
39
  return { state: 'unverified' };
39
- // `:-2` resolves the outpoint to its origin before returning metadata.
40
- // Querying the raw outpoint is wrong for anything already moved or listed
41
- // an OrdLock output carries no inscription, so ORDFS answers with an empty
42
- // record rather than the asset.
40
+ // `:-2` is only an ORDFS request suffix (resolve tip → origin metadata).
41
+ // It is not part of asset identity and must not be required to match
42
+ // response map keys beyond looking up the bulk result.
43
43
  const key = `${origin}:-2`;
44
- // Called on the client, not detached — these are class methods that use `this`.
45
44
  const res = await withTimeout(ordfs.bulkMetadata([key]));
46
- const meta = res?.[key] ?? res?.[origin];
45
+ // Prefer exact key, then bare origin, then any record that carried content.
46
+ const meta = res?.[key] ??
47
+ res?.[origin] ??
48
+ Object.values(res ?? {}).find((m) => !!m?.contentType);
47
49
  // An empty record means "nothing inscribed here", not a description of the
48
50
  // asset — treat it as no answer rather than as evidence.
49
51
  if (!meta?.contentType)
50
52
  return { state: 'unverified' };
51
53
  const resolved = {
52
54
  contentType: meta.contentType,
53
- contentLength: meta.contentLength,
54
55
  // ORDFS resolves the true genesis; the tagged value is usually the
55
56
  // seller's listing outpoint. Not treated as a mismatch — the claimed
56
57
  // value is an outpoint by construction, not a competing assertion.
@@ -86,8 +87,11 @@ async function verifyOpns(services, name, origin) {
86
87
  }
87
88
  return { state: 'verified' };
88
89
  }
89
- /** Verify a BSV21 token is active on the overlay. */
90
- async function verifyBsv21(services, tokenId, claimedSym) {
90
+ /**
91
+ * Verify a BSV21 token is active and that spent inputs are valid unspent
92
+ * outs on the token overlay topic.
93
+ */
94
+ async function verifyBsv21(services, tokenId, claimedSym, inputOutpoints = []) {
91
95
  const bsv21 = services.bsv21;
92
96
  if (typeof bsv21?.getTokenDetails !== 'function')
93
97
  return { state: 'unverified' };
@@ -98,20 +102,60 @@ async function verifyBsv21(services, tokenId, claimedSym) {
98
102
  return { state: 'mismatch', note: 'Token is not active on the overlay' };
99
103
  }
100
104
  const sym = res.token?.sym;
101
- if (claimedSym && sym && claimedSym !== sym) {
102
- return { state: 'mismatch', note: `Token symbol is ${sym}, not ${claimedSym}` };
105
+ // Tags are lowercased by BRC-100; CI/overlay preserve case — compare ignore-case.
106
+ if (claimedSym &&
107
+ sym &&
108
+ claimedSym.toLowerCase() !== sym.toLowerCase()) {
109
+ return {
110
+ state: 'mismatch',
111
+ note: `Token symbol is ${sym}, not ${claimedSym}`,
112
+ };
103
113
  }
104
- return { state: 'verified' };
114
+ // Validate spent token UTXOs against the overlay (same check sendBsv21 uses).
115
+ if (inputOutpoints.length > 0 && typeof bsv21.validateOutputs === 'function') {
116
+ const validated = await withTimeout(bsv21.validateOutputs(tokenId, inputOutpoints, { unspent: true }));
117
+ if (!validated)
118
+ return { state: 'unverified' };
119
+ const ok = new Set(validated.map((v) => formatOrdinalOutpoint(v.outpoint)));
120
+ const missing = inputOutpoints.filter((op) => !ok.has(formatOrdinalOutpoint(op)));
121
+ if (missing.length > 0) {
122
+ return {
123
+ state: 'mismatch',
124
+ note: missing.length === 1
125
+ ? 'A spent token output is not valid on the overlay'
126
+ : `${missing.length} spent token outputs are not valid on the overlay`,
127
+ };
128
+ }
129
+ }
130
+ return {
131
+ state: 'verified',
132
+ // Case-preserving symbol from overlay for the card subtitle.
133
+ ...(sym ? { name: sym } : {}),
134
+ };
105
135
  }
106
136
  /**
107
- * Verify the assets on a purchase intent.
137
+ * Verify assets on a purchase or BSV21 transfer.
108
138
  *
109
139
  * Returns `unverified` for anything we cannot positively confirm, including
110
140
  * when no services are wired at all. Never throws.
111
141
  */
112
- export async function verifyIntent(services, p1satIntent, inputs, outputs, contentUrlForOrigin) {
113
- if (!services || !p1satIntent)
142
+ export async function verifyIntent(services,
143
+ /** Prompt kind from script/heuristic classify, or legacy intent id. */
144
+ kindOrIntent, inputs, outputs, contentUrlForOrigin) {
145
+ if (!services || !kindOrIntent)
114
146
  return { state: 'unverified' };
147
+ const isPurchase = kindOrIntent === 'purchase' || kindOrIntent.endsWith('.purchase');
148
+ const isTokenTransfer = kindOrIntent === 'token-transfer' ||
149
+ kindOrIntent.startsWith('bsv21.');
150
+ if (!isPurchase && !isTokenTransfer)
151
+ return { state: 'unverified' };
152
+ const debug = {
153
+ kindOrIntent,
154
+ hasOrdfs: !!services.ordfs,
155
+ hasBulk: typeof services.ordfs?.bulkMetadata === 'function',
156
+ inputTagSets: inputs.map((i) => i.tags),
157
+ outputTagSets: outputs.map((o) => o.tags),
158
+ };
115
159
  try {
116
160
  const allTags = [...inputs.map((i) => i.tags), ...outputs.map((o) => o.tags)];
117
161
  const findAll = (key) => allTags.flatMap((tags) => tags
@@ -125,36 +169,72 @@ export async function verifyIntent(services, p1satIntent, inputs, outputs, conte
125
169
  }
126
170
  return undefined;
127
171
  };
128
- switch (p1satIntent) {
129
- case 'ordinal.purchase': {
130
- const origin = find('origin');
131
- if (!origin)
132
- return { state: 'unverified' };
133
- const res = await verifyOrdinal(services, origin, findAll('type'));
134
- // Preview URL follows the *resolved* origin, not the tagged one —
135
- // a listing outpoint has no content to serve.
136
- return res.origin && contentUrlForOrigin
137
- ? { ...res, contentUrl: contentUrlForOrigin(res.origin) }
138
- : res;
172
+ // BSV21: token active + spent inputs valid on overlay.
173
+ const tokenId = find('bsv21');
174
+ if (tokenId ||
175
+ kindOrIntent === 'bsv21.purchase' ||
176
+ kindOrIntent === 'token-transfer' ||
177
+ kindOrIntent.startsWith('bsv21.')) {
178
+ if (!tokenId)
179
+ return { state: 'unverified' };
180
+ const tokenInputs = inputs.filter((i) => i.basket?.includes('bsv21') ||
181
+ i.tags.some((t) => t.startsWith('bsv21:')));
182
+ const outpoints = tokenInputs
183
+ .map((i) => i.outpoint)
184
+ .filter(Boolean);
185
+ // Prefer case-preserving CI sym over lowercased tags.
186
+ let claimedSym = find('sym');
187
+ for (const inp of inputs) {
188
+ if (!inp.customInstructions)
189
+ continue;
190
+ try {
191
+ const s = JSON.parse(inp.customInstructions).sym;
192
+ if (typeof s === 'string' && s.trim()) {
193
+ claimedSym = s.trim();
194
+ break;
195
+ }
196
+ }
197
+ catch {
198
+ // ignore
199
+ }
139
200
  }
140
- case 'opns.purchase': {
141
- const name = find('name');
142
- const origin = find('origin');
143
- if (!name || !origin)
144
- return { state: 'unverified' };
145
- return await verifyOpns(services, name, origin);
201
+ return await verifyBsv21(services, tokenId, claimedSym, outpoints);
202
+ }
203
+ const name = find('name');
204
+ const origin = find('origin');
205
+ debug.name = name;
206
+ debug.origin = origin;
207
+ if ((name && origin && outputs.some((o) => o.basket?.includes('opns'))) ||
208
+ kindOrIntent === 'opns.purchase') {
209
+ if (!name || !origin)
210
+ return { state: 'unverified' };
211
+ return await verifyOpns(services, name, origin);
212
+ }
213
+ if (!origin) {
214
+ debug.reason = 'no-origin-tag';
215
+ globalThis.__lastVerify = debug;
216
+ return { state: 'unverified' };
217
+ }
218
+ const res = await verifyOrdinal(services, origin, findAll('type'));
219
+ debug.verifyOrdinal = res;
220
+ // contentUrl is optional polish — never let a URL helper wipe a verified result
221
+ // (e.g. unbound getContentUrl losing `this` and throwing).
222
+ if (res.origin && contentUrlForOrigin) {
223
+ try {
224
+ res.contentUrl = contentUrlForOrigin(res.origin);
146
225
  }
147
- case 'bsv21.purchase': {
148
- const tokenId = find('bsv21');
149
- if (!tokenId)
150
- return { state: 'unverified' };
151
- return await verifyBsv21(services, tokenId, find('sym'));
226
+ catch (e) {
227
+ debug.contentUrlError = String(e);
152
228
  }
153
- default:
154
- return { state: 'unverified' };
155
229
  }
230
+ ;
231
+ globalThis.__lastVerify = debug;
232
+ return res;
156
233
  }
157
- catch {
234
+ catch (e) {
235
+ debug.error = String(e);
236
+ globalThis.__lastVerify =
237
+ debug;
158
238
  return { state: 'unverified' };
159
239
  }
160
240
  }