@oxy.so/core 1.7.1 → 1.7.3

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.
@@ -391,10 +391,10 @@ export declare function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(B
391
391
  /**
392
392
  * Whether this process can prove what it is (ADR 0026).
393
393
  *
394
- * The check and the module that performs it are loaded LAZILY and only on a
395
- * Node host. `@oxy.so/core`'s root barrel reaches React Native and Expo, and
396
- * `server/workloadIdentity` imports `node:crypto` — a static import here
397
- * would pull it into every mobile bundle for a path a phone can never take.
394
+ * The internal package subpath selects a client implementation for native
395
+ * and browser bundlers, and the signer only for Node hosts. The runtime
396
+ * Node guard avoids calling attestation on clients; the module boundary
397
+ * keeps node:crypto out of their bundle graphs (a guard alone cannot).
398
398
  *
399
399
  * @internal
400
400
  */
@@ -0,0 +1,4 @@
1
+ import type { WorkloadServiceToken, WorkloadServiceTokenOptions } from './workloadIdentity';
2
+ /** Workload attestation belongs to a Node host, never a browser or device. */
3
+ export declare function canAttestWorkloadIdentity(): boolean;
4
+ export declare function requestWorkloadServiceToken(_options: WorkloadServiceTokenOptions): Promise<WorkloadServiceToken>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxy.so/core",
3
- "version": "1.7.1",
3
+ "version": "1.7.3",
4
4
  "description": "OxyHQ SDK Foundation — API client, authentication, cryptographic identity, and shared utilities",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -59,7 +59,17 @@
59
59
  },
60
60
  "default": "./dist/esm/logger/index.js"
61
61
  },
62
- "./package.json": "./package.json"
62
+ "./package.json": "./package.json",
63
+ "./internal/workload-identity": {
64
+ "types": "./dist/types/server/workloadIdentity.d.ts",
65
+ "react-native": "./dist/esm/server/workloadIdentity.client.js",
66
+ "browser": "./dist/esm/server/workloadIdentity.client.js",
67
+ "node": {
68
+ "import": "./dist/esm/server/workloadIdentity.js",
69
+ "require": "./dist/cjs/server/workloadIdentity.js"
70
+ },
71
+ "default": "./dist/esm/server/workloadIdentity.client.js"
72
+ }
63
73
  },
64
74
  "files": [
65
75
  "NOTICE",
@@ -119,7 +129,7 @@
119
129
  "@noble/ciphers": "^1.3.0",
120
130
  "@noble/hashes": "^1.8.0",
121
131
  "@oxy.so/contracts": "^1.3.0",
122
- "@oxy.so/protocol": "^1.0.1",
132
+ "@oxy.so/protocol": "^1.1.0",
123
133
  "@scure/bip39": "^1.6.0",
124
134
  "buffer": "^6.0.3",
125
135
  "express-rate-limit": "^8.6.0",
@@ -647,17 +647,17 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
647
647
  /**
648
648
  * Whether this process can prove what it is (ADR 0026).
649
649
  *
650
- * The check and the module that performs it are loaded LAZILY and only on a
651
- * Node host. `@oxy.so/core`'s root barrel reaches React Native and Expo, and
652
- * `server/workloadIdentity` imports `node:crypto` — a static import here
653
- * would pull it into every mobile bundle for a path a phone can never take.
650
+ * The internal package subpath selects a client implementation for native
651
+ * and browser bundlers, and the signer only for Node hosts. The runtime
652
+ * Node guard avoids calling attestation on clients; the module boundary
653
+ * keeps node:crypto out of their bundle graphs (a guard alone cannot).
654
654
  *
655
655
  * @internal
656
656
  */
657
657
  async _canUseWorkloadIdentity(): Promise<boolean> {
658
658
  if (typeof process === 'undefined' || !process.versions?.node) return false;
659
659
  try {
660
- const { canAttestWorkloadIdentity } = await import('../server/workloadIdentity');
660
+ const { canAttestWorkloadIdentity } = await import('@oxy.so/core/internal/workload-identity');
661
661
  return canAttestWorkloadIdentity();
662
662
  } catch {
663
663
  // A bundler that dropped the server subpath, or a runtime without it.
@@ -684,7 +684,7 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
684
684
  if (entry?.token && entry.expiresAt > now + 60_000) return entry.token;
685
685
  if (entry?.pending) return entry.pending;
686
686
 
687
- const { requestWorkloadServiceToken } = await import('../server/workloadIdentity');
687
+ const { requestWorkloadServiceToken } = await import('@oxy.so/core/internal/workload-identity');
688
688
  const seeded = entry ?? {
689
689
  token: '',
690
690
  expiresAt: 0,
@@ -0,0 +1,16 @@
1
+ import { canAttestWorkloadIdentity, requestWorkloadServiceToken } from '../workloadIdentity.client';
2
+
3
+ describe('client workload identity boundary', () => {
4
+ it('cannot attest even when Node process globals are present', () => {
5
+ expect(process.versions.node).toBeTruthy();
6
+ expect(canAttestWorkloadIdentity()).toBe(false);
7
+ });
8
+
9
+ it('rejects before contacting a server when explicitly requested', async () => {
10
+ const fetchSpy = jest.spyOn(globalThis, 'fetch');
11
+ await expect(requestWorkloadServiceToken({ baseUrl: 'https://example.test' }))
12
+ .rejects.toThrow('only available on a Node host');
13
+ expect(fetchSpy).not.toHaveBeenCalled();
14
+ fetchSpy.mockRestore();
15
+ });
16
+ });
@@ -0,0 +1,12 @@
1
+ import type { WorkloadServiceToken, WorkloadServiceTokenOptions } from './workloadIdentity';
2
+
3
+ /** Workload attestation belongs to a Node host, never a browser or device. */
4
+ export function canAttestWorkloadIdentity(): boolean {
5
+ return false;
6
+ }
7
+
8
+ export async function requestWorkloadServiceToken(
9
+ _options: WorkloadServiceTokenOptions,
10
+ ): Promise<WorkloadServiceToken> {
11
+ throw new Error('Workload identity is only available on a Node host');
12
+ }