@townco/secret 0.1.33 → 0.1.34

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.
@@ -3,201 +3,201 @@
3
3
  * methods to detect changes and generate appropriate `op` CLI commands.
4
4
  */
5
5
  export class OnePassword {
6
- vault;
7
- item;
8
- fields;
9
- originalFields;
10
- constructor(vault, item, fields = new Map()) {
11
- this.vault = vault;
12
- this.item = item;
13
- this.fields = new Map(fields);
14
- this.originalFields = new Map(fields);
15
- }
16
- /**
17
- * Create an OpItem from a 1Password FullItem JSON response
18
- */
19
- static fromFullItem(vault, itemName, fullItem) {
20
- const fields = new Map();
21
- if (fullItem.fields) {
22
- for (const field of fullItem.fields) {
23
- if (field.label && field.value) {
24
- fields.set(field.label, field.value);
25
- }
26
- }
27
- }
28
- return new OnePassword(vault, itemName, fields);
29
- }
30
- /**
31
- * Fetch an OpItem from 1Password using the CLI
32
- */
33
- static async fetch(vault, item) {
34
- try {
35
- const proc = Bun.spawn([
36
- "op",
37
- "--format=json",
38
- "item",
39
- "get",
40
- "--vault",
41
- vault,
42
- item,
43
- ]);
44
- const output = await new Response(proc.stdout).text();
45
- await proc.exited;
46
- const fullItem = JSON.parse(output);
47
- return OnePassword.fromFullItem(vault, item, fullItem);
48
- } catch (error) {
49
- throw new Error(
50
- `Failed to fetch item '${item}' from vault '${vault}': ${error}`,
51
- );
52
- }
53
- }
54
- /**
55
- * Sign in to 1Password CLI
56
- */
57
- static async signin() {
58
- await Bun.spawn(["op", "signin"]).exited;
59
- }
60
- /**
61
- * Get a field value
62
- */
63
- get(key) {
64
- return this.fields.get(key);
65
- }
66
- /**
67
- * Set a field value (marks as changed)
68
- */
69
- set(key, value) {
70
- this.fields.set(key, value);
71
- return this;
72
- }
73
- /**
74
- * Delete a field (marks as deleted)
75
- */
76
- delete(key) {
77
- this.fields.delete(key);
78
- return this;
79
- }
80
- /**
81
- * Check if a field exists
82
- */
83
- has(key) {
84
- return this.fields.has(key);
85
- }
86
- /**
87
- * Get all field keys
88
- */
89
- keys() {
90
- return Array.from(this.fields.keys());
91
- }
92
- /**
93
- * Get all fields as a record
94
- */
95
- toRecord() {
96
- return Object.fromEntries(this.fields);
97
- }
98
- /**
99
- * Get all field entries
100
- */
101
- entries() {
102
- return this.fields.entries();
103
- }
104
- /**
105
- * Build an op:// reference for a field
106
- */
107
- getReference(key) {
108
- return `op://${this.vault}/${this.item}/${key}`;
109
- }
110
- /**
111
- * Detect changes between original and current state
112
- */
113
- detectChanges() {
114
- const changes = [];
115
- // Check for deletions
116
- for (const key of this.originalFields.keys()) {
117
- if (!this.fields.has(key)) {
118
- changes.push({ type: "delete", key });
119
- }
120
- }
121
- // Check for additions and updates
122
- for (const [key, value] of this.fields.entries()) {
123
- const originalValue = this.originalFields.get(key);
124
- if (originalValue === undefined) {
125
- changes.push({ type: "add", key, value });
126
- } else if (originalValue !== value) {
127
- changes.push({ type: "update", key, value });
128
- }
129
- }
130
- return changes;
131
- }
132
- /**
133
- * Generate op CLI arguments for a single change
134
- */
135
- buildEditArgs(change) {
136
- switch (change.type) {
137
- case "add":
138
- case "update":
139
- return [`${change.key}[password]=${change.value}`];
140
- case "delete":
141
- return [`${change.key}[delete]`];
142
- }
143
- }
144
- /**
145
- * Apply all changes to 1Password using the op CLI
146
- * Returns the number of changes applied
147
- */
148
- async sync() {
149
- const changes = this.detectChanges();
150
- if (changes.length === 0) {
151
- return 0;
152
- }
153
- // Build all edit arguments
154
- const editArgs = changes.flatMap((change) => this.buildEditArgs(change));
155
- // Execute a single op item edit command with all changes
156
- await Bun.spawn([
157
- "op",
158
- "item",
159
- "edit",
160
- this.item,
161
- "--vault",
162
- this.vault,
163
- ...editArgs,
164
- ]).exited;
165
- // Update originalFields to match current state
166
- this.originalFields = new Map(this.fields);
167
- return changes.length;
168
- }
169
- /**
170
- * Inject secrets from a template file to an output file
171
- * This resolves op:// references to actual values
172
- */
173
- static async inject(inputPath, outputPath) {
174
- await Bun.spawn([
175
- "op",
176
- "inject",
177
- "-i",
178
- inputPath,
179
- "-o",
180
- outputPath,
181
- "--force",
182
- ]).exited;
183
- }
184
- /**
185
- * Create a clone of this OpItem
186
- */
187
- clone() {
188
- return new OnePassword(this.vault, this.item, new Map(this.fields));
189
- }
190
- /**
191
- * Reset to original state (discard changes)
192
- */
193
- reset() {
194
- this.fields = new Map(this.originalFields);
195
- return this;
196
- }
197
- /**
198
- * Check if there are unsaved changes
199
- */
200
- hasChanges() {
201
- return this.detectChanges().length > 0;
202
- }
6
+ vault;
7
+ item;
8
+ fields;
9
+ originalFields;
10
+ constructor(vault, item, fields = new Map()) {
11
+ this.vault = vault;
12
+ this.item = item;
13
+ this.fields = new Map(fields);
14
+ this.originalFields = new Map(fields);
15
+ }
16
+ /**
17
+ * Create an OpItem from a 1Password FullItem JSON response
18
+ */
19
+ static fromFullItem(vault, itemName, fullItem) {
20
+ const fields = new Map();
21
+ if (fullItem.fields) {
22
+ for (const field of fullItem.fields) {
23
+ if (field.label && field.value) {
24
+ fields.set(field.label, field.value);
25
+ }
26
+ }
27
+ }
28
+ return new OnePassword(vault, itemName, fields);
29
+ }
30
+ /**
31
+ * Fetch an OpItem from 1Password using the CLI
32
+ */
33
+ static async fetch(vault, item) {
34
+ try {
35
+ const proc = Bun.spawn([
36
+ "op",
37
+ "--format=json",
38
+ "item",
39
+ "get",
40
+ "--vault",
41
+ vault,
42
+ item,
43
+ ]);
44
+ const output = await new Response(proc.stdout).text();
45
+ await proc.exited;
46
+ const fullItem = JSON.parse(output);
47
+ return OnePassword.fromFullItem(vault, item, fullItem);
48
+ }
49
+ catch (error) {
50
+ throw new Error(`Failed to fetch item '${item}' from vault '${vault}': ${error}`);
51
+ }
52
+ }
53
+ /**
54
+ * Sign in to 1Password CLI
55
+ */
56
+ static async signin() {
57
+ await Bun.spawn(["op", "signin"]).exited;
58
+ }
59
+ /**
60
+ * Get a field value
61
+ */
62
+ get(key) {
63
+ return this.fields.get(key);
64
+ }
65
+ /**
66
+ * Set a field value (marks as changed)
67
+ */
68
+ set(key, value) {
69
+ this.fields.set(key, value);
70
+ return this;
71
+ }
72
+ /**
73
+ * Delete a field (marks as deleted)
74
+ */
75
+ delete(key) {
76
+ this.fields.delete(key);
77
+ return this;
78
+ }
79
+ /**
80
+ * Check if a field exists
81
+ */
82
+ has(key) {
83
+ return this.fields.has(key);
84
+ }
85
+ /**
86
+ * Get all field keys
87
+ */
88
+ keys() {
89
+ return Array.from(this.fields.keys());
90
+ }
91
+ /**
92
+ * Get all fields as a record
93
+ */
94
+ toRecord() {
95
+ return Object.fromEntries(this.fields);
96
+ }
97
+ /**
98
+ * Get all field entries
99
+ */
100
+ entries() {
101
+ return this.fields.entries();
102
+ }
103
+ /**
104
+ * Build an op:// reference for a field
105
+ */
106
+ getReference(key) {
107
+ return `op://${this.vault}/${this.item}/${key}`;
108
+ }
109
+ /**
110
+ * Detect changes between original and current state
111
+ */
112
+ detectChanges() {
113
+ const changes = [];
114
+ // Check for deletions
115
+ for (const key of this.originalFields.keys()) {
116
+ if (!this.fields.has(key)) {
117
+ changes.push({ type: "delete", key });
118
+ }
119
+ }
120
+ // Check for additions and updates
121
+ for (const [key, value] of this.fields.entries()) {
122
+ const originalValue = this.originalFields.get(key);
123
+ if (originalValue === undefined) {
124
+ changes.push({ type: "add", key, value });
125
+ }
126
+ else if (originalValue !== value) {
127
+ changes.push({ type: "update", key, value });
128
+ }
129
+ }
130
+ return changes;
131
+ }
132
+ /**
133
+ * Generate op CLI arguments for a single change
134
+ */
135
+ buildEditArgs(change) {
136
+ switch (change.type) {
137
+ case "add":
138
+ case "update":
139
+ return [`${change.key}[password]=${change.value}`];
140
+ case "delete":
141
+ return [`${change.key}[delete]`];
142
+ }
143
+ }
144
+ /**
145
+ * Apply all changes to 1Password using the op CLI
146
+ * Returns the number of changes applied
147
+ */
148
+ async sync() {
149
+ const changes = this.detectChanges();
150
+ if (changes.length === 0) {
151
+ return 0;
152
+ }
153
+ // Build all edit arguments
154
+ const editArgs = changes.flatMap((change) => this.buildEditArgs(change));
155
+ // Execute a single op item edit command with all changes
156
+ await Bun.spawn([
157
+ "op",
158
+ "item",
159
+ "edit",
160
+ this.item,
161
+ "--vault",
162
+ this.vault,
163
+ ...editArgs,
164
+ ]).exited;
165
+ // Update originalFields to match current state
166
+ this.originalFields = new Map(this.fields);
167
+ return changes.length;
168
+ }
169
+ /**
170
+ * Inject secrets from a template file to an output file
171
+ * This resolves op:// references to actual values
172
+ */
173
+ static async inject(inputPath, outputPath) {
174
+ await Bun.spawn([
175
+ "op",
176
+ "inject",
177
+ "-i",
178
+ inputPath,
179
+ "-o",
180
+ outputPath,
181
+ "--force",
182
+ ]).exited;
183
+ }
184
+ /**
185
+ * Create a clone of this OpItem
186
+ */
187
+ clone() {
188
+ return new OnePassword(this.vault, this.item, new Map(this.fields));
189
+ }
190
+ /**
191
+ * Reset to original state (discard changes)
192
+ */
193
+ reset() {
194
+ this.fields = new Map(this.originalFields);
195
+ return this;
196
+ }
197
+ /**
198
+ * Check if there are unsaved changes
199
+ */
200
+ hasChanges() {
201
+ return this.detectChanges().length > 0;
202
+ }
203
203
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@townco/secret",
3
- "version": "0.1.33",
3
+ "version": "0.1.34",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -23,7 +23,7 @@
23
23
  "@1password/connect": "^1.4.2"
24
24
  },
25
25
  "devDependencies": {
26
- "@townco/tsconfig": "0.1.30",
26
+ "@townco/tsconfig": "0.1.31",
27
27
  "@types/bun": "^1.3.1"
28
28
  }
29
29
  }