orizu 0.1.6 → 0.2.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orizu",
3
- "version": "0.1.6",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,7 +13,12 @@ import {
13
13
  import { join } from 'path'
14
14
  import { homedir } from 'os'
15
15
  import { randomBytes } from 'crypto'
16
- import { ServerCredentials, StoredCredentialsV1, StoredCredentialsV2 } from './types.js'
16
+ import {
17
+ ServerCredentials,
18
+ StoredCredentialsV1,
19
+ StoredCredentialsV2,
20
+ StoredCredentialsV3,
21
+ } from './types.js'
17
22
 
18
23
  function getConfigDir(): string {
19
24
  if (process.env.ORIZU_CONFIG_DIR) {
@@ -35,6 +40,15 @@ function isStoredCredentialsV2(value: unknown): value is StoredCredentialsV2 {
35
40
  return typed.version === 2 && !!typed.servers && typeof typed.servers === 'object'
36
41
  }
37
42
 
43
+ function isStoredCredentialsV3(value: unknown): value is StoredCredentialsV3 {
44
+ if (!value || typeof value !== 'object') {
45
+ return false
46
+ }
47
+
48
+ const typed = value as Partial<StoredCredentialsV3>
49
+ return typed.version === 3 && !!typed.servers && typeof typed.servers === 'object'
50
+ }
51
+
38
52
  function isStoredCredentialsV1(value: unknown): value is StoredCredentialsV1 {
39
53
  if (!value || typeof value !== 'object') {
40
54
  return false
@@ -63,7 +77,7 @@ function migrateToV2(stored: StoredCredentialsV1): StoredCredentialsV2 {
63
77
  }
64
78
  }
65
79
 
66
- function writeCredentials(config: StoredCredentialsV2) {
80
+ function writeCredentials(config: StoredCredentialsV2 | StoredCredentialsV3) {
67
81
  const dir = getConfigDir()
68
82
  mkdirSync(dir, { recursive: true, mode: 0o700 })
69
83
  chmodSync(dir, 0o700)
@@ -98,15 +112,15 @@ function writeCredentials(config: StoredCredentialsV2) {
98
112
  chmodSync(path, 0o600)
99
113
  }
100
114
 
101
- function createEmptyCredentialsConfig(): StoredCredentialsV2 {
115
+ function createEmptyCredentialsConfig(): StoredCredentialsV3 {
102
116
  return {
103
- version: 2 as const,
117
+ version: 3 as const,
104
118
  activeBaseUrl: null,
105
119
  servers: {},
106
120
  }
107
121
  }
108
122
 
109
- function loadCredentialsConfigForWrite(): StoredCredentialsV2 {
123
+ function loadCredentialsConfigForWrite(): StoredCredentialsV2 | StoredCredentialsV3 {
110
124
  try {
111
125
  return loadCredentialsConfig() || createEmptyCredentialsConfig()
112
126
  } catch {
@@ -114,7 +128,7 @@ function loadCredentialsConfigForWrite(): StoredCredentialsV2 {
114
128
  }
115
129
  }
116
130
 
117
- export function loadCredentialsConfig(): StoredCredentialsV2 | null {
131
+ export function loadCredentialsConfig(): StoredCredentialsV2 | StoredCredentialsV3 | null {
118
132
  const path = getCredentialsPath()
119
133
  if (!existsSync(path)) {
120
134
  return null
@@ -130,6 +144,10 @@ export function loadCredentialsConfig(): StoredCredentialsV2 | null {
130
144
  return null
131
145
  }
132
146
 
147
+ if (isStoredCredentialsV3(parsed)) {
148
+ return parsed
149
+ }
150
+
133
151
  if (isStoredCredentialsV2(parsed)) {
134
152
  return parsed
135
153
  }
@@ -156,7 +174,14 @@ export function getServerCredentials(baseUrl: string): ServerCredentials | null
156
174
  }
157
175
 
158
176
  export function saveServerCredentials(baseUrl: string, credentials: ServerCredentials) {
159
- const config = loadCredentialsConfigForWrite()
177
+ const loaded = loadCredentialsConfigForWrite()
178
+ const config: StoredCredentialsV3 = loaded.version === 3
179
+ ? loaded
180
+ : {
181
+ version: 3,
182
+ activeBaseUrl: loaded.activeBaseUrl,
183
+ servers: loaded.servers,
184
+ }
160
185
 
161
186
  config.servers[baseUrl] = credentials
162
187
  config.activeBaseUrl = baseUrl
@@ -164,7 +189,14 @@ export function saveServerCredentials(baseUrl: string, credentials: ServerCreden
164
189
  }
165
190
 
166
191
  export function updateServerCredentials(baseUrl: string, credentials: ServerCredentials) {
167
- const config = loadCredentialsConfigForWrite()
192
+ const loaded = loadCredentialsConfigForWrite()
193
+ const config: StoredCredentialsV3 = loaded.version === 3
194
+ ? loaded
195
+ : {
196
+ version: 3,
197
+ activeBaseUrl: loaded.activeBaseUrl,
198
+ servers: loaded.servers,
199
+ }
168
200
  config.servers[baseUrl] = credentials
169
201
  writeCredentials(config)
170
202
  }
package/src/http.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { getActiveBaseUrl, getServerCredentials, updateServerCredentials } from './credentials.js'
2
2
  import { getFlagBaseUrl, GlobalFlags, normalizeBaseUrl } from './global-flags.js'
3
- import { LoginResponse, ServerCredentials } from './types.js'
3
+ import { LoginResponse, ServerCredentials, SessionServerCredentials } from './types.js'
4
4
 
5
5
  let runtimeFlags: GlobalFlags = { local: false, server: null }
6
6
 
@@ -75,12 +75,24 @@ export function assertSecureTokenTransport(baseUrl: string) {
75
75
  )
76
76
  }
77
77
 
78
+ function isSessionCredentials(credentials: ServerCredentials): credentials is SessionServerCredentials {
79
+ return 'accessToken' in credentials
80
+ }
81
+
82
+ function getAuthorizationToken(credentials: ServerCredentials): string {
83
+ return isSessionCredentials(credentials) ? credentials.accessToken : credentials.apiKey
84
+ }
85
+
78
86
  function isExpired(expiresAt: number): boolean {
79
87
  const nowUnix = Math.floor(Date.now() / 1000)
80
88
  return expiresAt <= nowUnix + 30
81
89
  }
82
90
 
83
91
  async function refreshCredentials(baseUrl: string, credentials: ServerCredentials): Promise<ServerCredentials> {
92
+ if (!isSessionCredentials(credentials)) {
93
+ throw new Error('API key credentials do not refresh. Run `orizu login` again if access fails.')
94
+ }
95
+
84
96
  assertSecureTokenTransport(baseUrl)
85
97
  const response = await fetch(`${baseUrl}/api/cli/auth/refresh`, {
86
98
  method: 'POST',
@@ -93,7 +105,12 @@ async function refreshCredentials(baseUrl: string, credentials: ServerCredential
93
105
  }
94
106
 
95
107
  const data = await response.json() as LoginResponse
108
+ if (!data.accessToken || !data.refreshToken || !data.expiresAt) {
109
+ throw new Error('Server returned invalid refresh credentials. Run `orizu login` again.')
110
+ }
111
+
96
112
  const refreshed = {
113
+ credentialType: 'session' as const,
97
114
  accessToken: data.accessToken,
98
115
  refreshToken: data.refreshToken,
99
116
  expiresAt: data.expiresAt,
@@ -111,7 +128,7 @@ export async function authedFetch(path: string, init: RequestInit = {}) {
111
128
  }
112
129
 
113
130
  let activeCredentials = credentials
114
- if (isExpired(activeCredentials.expiresAt)) {
131
+ if (isSessionCredentials(activeCredentials) && isExpired(activeCredentials.expiresAt)) {
115
132
  activeCredentials = await refreshCredentials(baseUrl, activeCredentials)
116
133
  }
117
134
 
@@ -119,17 +136,17 @@ export async function authedFetch(path: string, init: RequestInit = {}) {
119
136
  ...init,
120
137
  headers: {
121
138
  ...(init.headers || {}),
122
- Authorization: `Bearer ${activeCredentials.accessToken}`,
139
+ Authorization: `Bearer ${getAuthorizationToken(activeCredentials)}`,
123
140
  },
124
141
  })
125
142
 
126
- if (response.status === 401) {
143
+ if (response.status === 401 && isSessionCredentials(activeCredentials)) {
127
144
  activeCredentials = await refreshCredentials(baseUrl, activeCredentials)
128
145
  response = await fetch(`${baseUrl}${path}`, {
129
146
  ...init,
130
147
  headers: {
131
148
  ...(init.headers || {}),
132
- Authorization: `Bearer ${activeCredentials.accessToken}`,
149
+ Authorization: `Bearer ${getAuthorizationToken(activeCredentials)}`,
133
150
  },
134
151
  })
135
152
  }