@pikku/core 0.12.19 → 0.12.20

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.
@@ -72,6 +72,54 @@ async function resolveSession(
72
72
  * @param parentServices - The parent/caller's singleton services (used as base)
73
73
  * @returns The package's singleton services
74
74
  */
75
+ /**
76
+ * Find the consumer-defined namespace (from wireAddon) for a given addon package.
77
+ * Returns null if the package isn't registered as an addon.
78
+ */
79
+ const findAddonNamespaceForPackage = (packageName: string): string | null => {
80
+ const addons = pikkuState(null, 'addons', 'packages')
81
+ if (!addons) return null
82
+ for (const [namespace, cfg] of addons.entries()) {
83
+ if (cfg?.package === packageName) return namespace
84
+ }
85
+ return null
86
+ }
87
+
88
+ /**
89
+ * Wrap a workflow service so that bare workflow names passed from inside an
90
+ * addon function are auto-prefixed with the addon's consumer-facing namespace.
91
+ * Without this, `runToCompletion('myWorkflow')` from inside an addon misses
92
+ * the workflow registered under the addon's package scope and throws
93
+ * WorkflowNotFoundError — forcing addons to hardcode their consumer-defined
94
+ * namespace, which couples the addon to its caller.
95
+ *
96
+ * Explicit `'ns:name'` and bare names that already exist in root meta are
97
+ * unaffected; only bare names that would otherwise miss resolution get
98
+ * prefixed.
99
+ */
100
+ const wrapWorkflowServiceForPackage = <T extends object>(
101
+ service: T,
102
+ packageName: string
103
+ ): T => {
104
+ return new Proxy(service, {
105
+ get(target, prop, receiver) {
106
+ if (prop === 'startWorkflow' || prop === 'runToCompletion') {
107
+ const original = Reflect.get(target, prop, receiver) as Function
108
+ return function (this: any, name: string, ...rest: any[]) {
109
+ if (typeof name === 'string' && !name.includes(':')) {
110
+ const namespace = findAddonNamespaceForPackage(packageName)
111
+ if (namespace) {
112
+ name = `${namespace}:${name}`
113
+ }
114
+ }
115
+ return original.call(this, name, ...rest)
116
+ }
117
+ }
118
+ return Reflect.get(target, prop, receiver)
119
+ },
120
+ })
121
+ }
122
+
75
123
  const getOrCreatePackageSingletonServices = async (
76
124
  packageName: string,
77
125
  parentServices: CoreSingletonServices
@@ -101,6 +149,18 @@ const getOrCreatePackageSingletonServices = async (
101
149
  parentServices
102
150
  )
103
151
 
152
+ // Wrap workflowService so that bare names used inside the addon's functions
153
+ // resolve to workflows registered under the addon's package scope.
154
+ if (
155
+ packageServices.workflowService &&
156
+ typeof packageServices.workflowService === 'object'
157
+ ) {
158
+ packageServices.workflowService = wrapWorkflowServiceForPackage(
159
+ packageServices.workflowService as object,
160
+ packageName
161
+ ) as typeof packageServices.workflowService
162
+ }
163
+
104
164
  // Cache the services
105
165
  pikkuState(packageName, 'package', 'singletonServices', packageServices)
106
166
 
@@ -378,11 +438,16 @@ export const runPikkuFunc = async <In = any, Out = any>(
378
438
  wireServices && Object.keys(wireServices).length > 0
379
439
  ? { ...resolvedSingletonServices, ...wireServices }
380
440
  : resolvedSingletonServices
441
+ const callerPackageName = packageName
381
442
  Object.defineProperty(resolvedWire, 'rpc', {
382
443
  get() {
383
- const rpc = rpcService.getContextRPCService(services, resolvedWire, {
384
- sessionService,
385
- })
444
+ const rpc = rpcService.getContextRPCService(
445
+ services,
446
+ resolvedWire,
447
+ { sessionService },
448
+ 0,
449
+ callerPackageName
450
+ )
386
451
  Object.defineProperty(resolvedWire, 'rpc', {
387
452
  value: rpc,
388
453
  writable: true,
package/src/index.ts CHANGED
@@ -98,7 +98,16 @@ export type { QueueService } from './wirings/queue/queue.types.js'
98
98
  export type { JWTService } from './services/jwt-service.js'
99
99
  export type { SecretService } from './services/secret-service.js'
100
100
  export type { VariablesService } from './services/variables-service.js'
101
- export type { ContentService } from './services/content-service.js'
101
+ export type {
102
+ ContentService,
103
+ SignContentKeyArgs,
104
+ SignURLArgs,
105
+ GetUploadURLArgs,
106
+ UploadURLResult,
107
+ BucketKeyArgs,
108
+ WriteFileArgs,
109
+ CopyFileArgs,
110
+ } from './services/content-service.js'
102
111
  export type { DeploymentService } from './services/deployment-service.js'
103
112
  export type { WorkflowService } from './services/workflow-service.js'
104
113
  export type { GatewayService } from './services/gateway-service.js'
@@ -1,81 +1,109 @@
1
- export interface ContentService {
1
+ /**
2
+ * Arguments for signing a content key into a time-limited URL.
3
+ */
4
+ export interface SignContentKeyArgs<TBucket extends string = string> {
5
+ bucket: TBucket
6
+ contentKey: string
7
+ dateLessThan: Date
8
+ dateGreaterThan?: Date
9
+ }
10
+
11
+ /**
12
+ * Arguments for signing an arbitrary URL.
13
+ */
14
+ export interface SignURLArgs {
15
+ url: string
16
+ dateLessThan: Date
17
+ dateGreaterThan?: Date
18
+ }
19
+
20
+ /**
21
+ * Arguments for minting a presigned upload URL.
22
+ */
23
+ export interface GetUploadURLArgs<TBucket extends string = string> {
24
+ bucket: TBucket
25
+ fileKey: string
26
+ contentType: string
27
+ size?: number
28
+ }
29
+
30
+ /**
31
+ * Result of minting a presigned upload URL.
32
+ */
33
+ export interface UploadURLResult {
34
+ uploadUrl: string
35
+ assetKey: string
36
+ uploadHeaders?: Record<string, string>
37
+ uploadMethod?: 'PUT' | 'POST'
38
+ }
39
+
40
+ /**
41
+ * Arguments for an operation that targets a single object by key.
42
+ */
43
+ export interface BucketKeyArgs<TBucket extends string = string> {
44
+ bucket: TBucket
45
+ key: string
46
+ }
47
+
48
+ /**
49
+ * Arguments for writing a stream to storage.
50
+ */
51
+ export interface WriteFileArgs<
52
+ TBucket extends string = string,
53
+ > extends BucketKeyArgs<TBucket> {
54
+ stream: ReadableStream | NodeJS.ReadableStream
55
+ }
56
+
57
+ /**
58
+ * Arguments for copying a local file into storage.
59
+ */
60
+ export interface CopyFileArgs<
61
+ TBucket extends string = string,
62
+ > extends BucketKeyArgs<TBucket> {
63
+ fromAbsolutePath: string
64
+ }
65
+
66
+ export interface ContentService<TBucket extends string = string> {
2
67
  /**
3
68
  * Signs a content key to generate a secure, time-limited access URL.
4
- * @param contentKey - The key representing the content object.
5
- * @param dateLessThan - The expiration time for the signed URL.
6
- * @param dateGreaterThan - (Optional) Start time before which access is denied.
7
69
  */
8
- signContentKey(
9
- contentKey: string,
10
- dateLessThan: Date,
11
- dateGreaterThan?: Date
12
- ): Promise<string>
70
+ signContentKey(args: SignContentKeyArgs<TBucket>): Promise<string>
13
71
 
14
72
  /**
15
73
  * Signs an arbitrary URL to generate a secure, time-limited access URL.
16
- * @param url - The full URL that needs signing.
17
- * @param dateLessThan - The expiration time for the signed URL.
18
- * @param dateGreaterThan - (Optional) Start time before which access is denied.
19
74
  */
20
- signURL(
21
- url: string,
22
- dateLessThan: Date,
23
- dateGreaterThan?: Date
24
- ): Promise<string>
75
+ signURL(args: SignURLArgs): Promise<string>
25
76
 
26
77
  /**
27
78
  * Generates a signed URL for uploading a file directly to storage.
28
- * @param fileKey - The desired key/location of the uploaded file.
29
- * @param contentType - The MIME type of the file.
30
- * @returns A signed upload URL and the finalized asset key.
79
+ * Bucket policy (size limits, MIME allowlist) is enforced by the implementation.
31
80
  */
32
- getUploadURL(
33
- fileKey: string,
34
- contentType: string
35
- ): Promise<{
36
- uploadUrl: string
37
- assetKey: string
38
- uploadHeaders?: Record<string, string>
39
- uploadMethod?: 'PUT' | 'POST'
40
- }>
81
+ getUploadURL(args: GetUploadURLArgs<TBucket>): Promise<UploadURLResult>
41
82
 
42
83
  /**
43
84
  * Deletes a file from the storage backend.
44
- * @param fileName - The name or key of the file to delete.
45
- * @returns A boolean indicating success.
46
85
  */
47
- deleteFile(fileName: string): Promise<boolean>
86
+ deleteFile(args: BucketKeyArgs<TBucket>): Promise<boolean>
48
87
 
49
88
  /**
50
- * Uploads a file stream to storage under a specified asset key.
51
- * @param assetKey - The key where the file will be saved.
52
- * @param stream - A readable stream of the file contents.
53
- * @returns A boolean indicating success.
89
+ * Uploads a file stream to storage under the specified bucket + key.
54
90
  */
55
- writeFile(
56
- assetKey: string,
57
- stream: ReadableStream | NodeJS.ReadableStream
58
- ): Promise<boolean>
91
+ writeFile(args: WriteFileArgs<TBucket>): Promise<boolean>
59
92
 
60
93
  /**
61
- * Copies a file from a local absolute path into storage under a new asset key.
62
- * @param assetKey - The destination key.
63
- * @param fromAbsolutePath - The local absolute file path.
64
- * @returns A boolean indicating success.
94
+ * Copies a file from a local absolute path into storage.
65
95
  */
66
- copyFile(assetKey: string, fromAbsolutePath: string): Promise<boolean>
96
+ copyFile(args: CopyFileArgs<TBucket>): Promise<boolean>
67
97
 
68
98
  /**
69
99
  * Reads a file from storage as a readable stream.
70
- * @param assetKey - The key of the file to read.
71
- * @returns A readable file stream.
72
100
  */
73
- readFile(assetKey: string): Promise<ReadableStream | NodeJS.ReadableStream>
101
+ readFile(
102
+ args: BucketKeyArgs<TBucket>
103
+ ): Promise<ReadableStream | NodeJS.ReadableStream>
74
104
 
75
105
  /**
76
106
  * Reads an entire file from storage into a Buffer.
77
- * @param assetKey - The key of the file to read.
78
- * @returns The file contents as a Buffer.
79
107
  */
80
- readFileAsBuffer(assetKey: string): Promise<Buffer>
108
+ readFileAsBuffer(args: BucketKeyArgs<TBucket>): Promise<Buffer>
81
109
  }
@@ -25,7 +25,16 @@ export { InMemoryQueueService } from './in-memory-queue-service.js'
25
25
  export { InMemoryTriggerService } from './in-memory-trigger-service.js'
26
26
  export { InMemoryAIRunStateService } from './in-memory-ai-run-state-service.js'
27
27
  export { LocalGatewayService } from './local-gateway-service.js'
28
- export type { ContentService } from './content-service.js'
28
+ export type {
29
+ ContentService,
30
+ SignContentKeyArgs,
31
+ SignURLArgs,
32
+ GetUploadURLArgs,
33
+ UploadURLResult,
34
+ BucketKeyArgs,
35
+ WriteFileArgs,
36
+ CopyFileArgs,
37
+ } from './content-service.js'
29
38
  export type { JWTService } from './jwt-service.js'
30
39
  export type { Logger } from './logger.js'
31
40
  export type { SecretService } from './secret-service.js'
@@ -1,7 +1,18 @@
1
1
  import { createReadStream, createWriteStream, promises } from 'fs'
2
2
  import { mkdir, readFile } from 'fs/promises'
3
3
  import { resolve, normalize } from 'path'
4
- import type { ContentService, JWTService, Logger } from '@pikku/core/services'
4
+ import type {
5
+ BucketKeyArgs,
6
+ ContentService,
7
+ CopyFileArgs,
8
+ GetUploadURLArgs,
9
+ JWTService,
10
+ Logger,
11
+ SignContentKeyArgs,
12
+ SignURLArgs,
13
+ UploadURLResult,
14
+ WriteFileArgs,
15
+ } from '@pikku/core/services'
5
16
  import { pipeline } from 'stream/promises'
6
17
  import type { Readable } from 'stream'
7
18
 
@@ -20,15 +31,20 @@ export class LocalContent implements ContentService {
20
31
  private jwt?: JWTService
21
32
  ) {}
22
33
 
23
- private safePath(assetKey: string): string {
34
+ private safePath(bucket: string, key: string): string {
24
35
  const base = resolve(this.config.localFileUploadPath)
25
- const target = resolve(base, normalize(assetKey))
36
+ const scoped = resolve(base, normalize(bucket))
37
+ const target = resolve(scoped, normalize(key))
26
38
  if (!target.startsWith(base + '/') && target !== base) {
27
39
  throw new Error('Invalid asset key')
28
40
  }
29
41
  return target
30
42
  }
31
43
 
44
+ private joinKey(bucket: string, key: string): string {
45
+ return `${bucket}/${key}`
46
+ }
47
+
32
48
  public async init() {}
33
49
 
34
50
  private async signParams(
@@ -58,105 +74,105 @@ export class LocalContent implements ContentService {
58
74
  return params.toString()
59
75
  }
60
76
 
61
- public async signURL(
62
- url: string,
63
- dateLessThan: Date,
64
- dateGreaterThan?: Date
65
- ): Promise<string> {
66
- const params = await this.signParams(dateLessThan, dateGreaterThan)
67
- return `${url}?${params}`
77
+ public async signURL(args: SignURLArgs): Promise<string> {
78
+ const params = await this.signParams(
79
+ args.dateLessThan,
80
+ args.dateGreaterThan
81
+ )
82
+ return `${args.url}?${params}`
68
83
  }
69
84
 
70
- public async signContentKey(
71
- assetKey: string,
72
- dateLessThan: Date,
73
- dateGreaterThan?: Date
74
- ): Promise<string> {
85
+ public async signContentKey(args: SignContentKeyArgs): Promise<string> {
86
+ const fullKey = this.joinKey(args.bucket, args.contentKey)
75
87
  const base = this.config.server
76
- ? `${this.config.server}${this.config.assetUrlPrefix}/${assetKey}`
77
- : `${this.config.assetUrlPrefix}/${assetKey}`
78
- return this.signURL(base, dateLessThan, dateGreaterThan)
88
+ ? `${this.config.server}${this.config.assetUrlPrefix}/${fullKey}`
89
+ : `${this.config.assetUrlPrefix}/${fullKey}`
90
+ return this.signURL({
91
+ url: base,
92
+ dateLessThan: args.dateLessThan,
93
+ dateGreaterThan: args.dateGreaterThan,
94
+ })
79
95
  }
80
96
 
81
- public async getUploadURL(assetKey: string) {
82
- this.logger.debug(`Going to upload with key: ${assetKey}`)
97
+ public async getUploadURL(args: GetUploadURLArgs): Promise<UploadURLResult> {
98
+ const fullKey = this.joinKey(args.bucket, args.fileKey)
99
+ this.logger.debug(`Going to upload with key: ${fullKey}`)
83
100
  return {
84
- uploadUrl: `${this.config.uploadUrlPrefix}/${assetKey}`,
85
- assetKey,
101
+ uploadUrl: `${this.config.uploadUrlPrefix}/${fullKey}`,
102
+ assetKey: fullKey,
86
103
  }
87
104
  }
88
105
 
89
- public async writeFile(
90
- assetKey: string,
91
- stream: ReadableStream | NodeJS.ReadableStream
92
- ): Promise<boolean> {
93
- this.logger.debug(`Writing file: ${assetKey}`)
106
+ public async writeFile(args: WriteFileArgs): Promise<boolean> {
107
+ this.logger.debug(`Writing file: ${args.bucket}/${args.key}`)
94
108
 
95
- const path = this.safePath(assetKey)
109
+ const path = this.safePath(args.bucket, args.key)
96
110
 
97
111
  try {
98
112
  await this.createDirectoryForFile(path)
99
113
  const fileStream = createWriteStream(path)
100
- // Use pipeline to properly manage stream piping and errors
101
- await pipeline(stream as Readable, fileStream)
114
+ await pipeline(args.stream as Readable, fileStream)
102
115
  return true
103
116
  } catch (e) {
104
117
  console.error(e)
105
- this.logger.error(`Error writing content ${assetKey}`, e)
118
+ this.logger.error(`Error writing content ${args.bucket}/${args.key}`, e)
106
119
  return false
107
120
  }
108
121
  }
109
122
 
110
- public async copyFile(
111
- assetKey: string,
112
- fromAbsolutePath: string
113
- ): Promise<boolean> {
114
- this.logger.debug(`Writing file: ${assetKey}`)
123
+ public async copyFile(args: CopyFileArgs): Promise<boolean> {
124
+ this.logger.debug(`Writing file: ${args.bucket}/${args.key}`)
115
125
  try {
116
- const path = this.safePath(assetKey)
126
+ const path = this.safePath(args.bucket, args.key)
117
127
  await this.createDirectoryForFile(path)
118
- await promises.copyFile(fromAbsolutePath, path)
128
+ await promises.copyFile(args.fromAbsolutePath, path)
129
+ return true
119
130
  } catch (e) {
120
131
  console.error(e)
121
- this.logger.error(`Error inserting content ${assetKey}`, e)
132
+ this.logger.error(`Error inserting content ${args.bucket}/${args.key}`, e)
122
133
  }
123
134
  return false
124
135
  }
125
136
 
126
137
  public async readFile(
127
- assetKey: string
138
+ args: BucketKeyArgs
128
139
  ): Promise<ReadableStream | NodeJS.ReadableStream> {
129
- this.logger.debug(`Getting key: ${assetKey}`)
140
+ this.logger.debug(`Getting key: ${args.bucket}/${args.key}`)
130
141
 
131
- const filePath = this.safePath(assetKey)
142
+ const filePath = this.safePath(args.bucket, args.key)
132
143
 
133
144
  try {
134
145
  const stream = createReadStream(filePath)
135
- // Handle early stream errors (like file not found, permission denied, etc.)
136
146
  stream.on('error', (err) => {
137
- this.logger.error(`Error getting content ${assetKey}`, err)
147
+ this.logger.error(
148
+ `Error getting content ${args.bucket}/${args.key}`,
149
+ err
150
+ )
138
151
  })
139
152
 
140
153
  return stream
141
154
  } catch (e) {
142
- this.logger.error(`Error setting up stream for ${assetKey}`, e)
155
+ this.logger.error(
156
+ `Error setting up stream for ${args.bucket}/${args.key}`,
157
+ e
158
+ )
143
159
  throw e
144
160
  }
145
161
  }
146
162
 
147
- public async readFileAsBuffer(assetKey: string): Promise<Buffer> {
148
- const filePath = this.safePath(assetKey)
149
- this.logger.debug(`Reading file as buffer: ${assetKey}`)
163
+ public async readFileAsBuffer(args: BucketKeyArgs): Promise<Buffer> {
164
+ const filePath = this.safePath(args.bucket, args.key)
165
+ this.logger.debug(`Reading file as buffer: ${args.bucket}/${args.key}`)
150
166
  return readFile(filePath)
151
167
  }
152
168
 
153
- public async deleteFile(assetKey: string): Promise<boolean> {
154
- this.logger.debug(`deleting key: ${assetKey}`)
169
+ public async deleteFile(args: BucketKeyArgs): Promise<boolean> {
170
+ this.logger.debug(`deleting key: ${args.bucket}/${args.key}`)
155
171
  try {
156
- await promises.unlink(this.safePath(assetKey))
172
+ await promises.unlink(this.safePath(args.bucket, args.key))
157
173
  return true
158
174
  } catch (e: any) {
159
- this.logger.error(`Error deleting content ${assetKey}`, e)
175
+ this.logger.error(`Error deleting content ${args.bucket}/${args.key}`, e)
160
176
  }
161
177
  return false
162
178
  }
@@ -54,7 +54,25 @@ export const resolveNamespace = (
54
54
  }
55
55
  }
56
56
 
57
- const getPikkuFunctionName = (rpcName: string): string => {
57
+ /**
58
+ * Resolve a bare (non-namespaced) RPC name to its pikkuFuncId, preferring
59
+ * the caller's addon package when provided. Returns the function name plus
60
+ * the package scope that resolved it (null = root), so callers can thread
61
+ * the scope into runPikkuFunc without a second lookup.
62
+ */
63
+ const resolvePikkuFunction = (
64
+ rpcName: string,
65
+ packageName: string | null = null
66
+ ): { pikkuFuncId: string; packageName: string | null } => {
67
+ // Addon-scoped calls: try the caller's package function meta first.
68
+ // (RPC meta only lives in root; addon functions are registered under their package.)
69
+ if (packageName) {
70
+ const pkgFunctions = pikkuState(packageName, 'function', 'meta')
71
+ const pkgMeta = pkgFunctions?.[rpcName]
72
+ if (pkgMeta) {
73
+ return { pikkuFuncId: pkgMeta.pikkuFuncId || rpcName, packageName }
74
+ }
75
+ }
58
76
  const rpc = pikkuState(null, 'rpc', 'meta')
59
77
  let rpcMeta = rpc[rpcName]
60
78
  if (!rpcMeta) {
@@ -66,7 +84,7 @@ const getPikkuFunctionName = (rpcName: string): string => {
66
84
  if (!rpcMeta) {
67
85
  throw new RPCNotFoundError(rpcName)
68
86
  }
69
- return rpcMeta
87
+ return { pikkuFuncId: rpcMeta, packageName: null }
70
88
  }
71
89
 
72
90
  // Context-aware RPC client for use within services
@@ -77,7 +95,8 @@ export class ContextAwareRPCService {
77
95
  private options: {
78
96
  requiresAuth?: boolean
79
97
  sessionService?: SessionService<CoreUserSession>
80
- }
98
+ },
99
+ private packageName: string | null = null
81
100
  ) {}
82
101
 
83
102
  public async rpcExposed(funcName: string, data: any): Promise<any> {
@@ -131,17 +150,22 @@ export class ContextAwareRPCService {
131
150
  }
132
151
  }
133
152
 
134
- // Try local function, then fall back to deployment service (remote)
153
+ // Bare name: resolve via caller's package scope first (if any), then root.
154
+ // Note: intra-addon bare calls do NOT re-apply the addon's external
155
+ // addonConfig.auth/tags — those gates are only applied on the external
156
+ // 'namespace:func' boundary via invokeAddonFunction.
135
157
  try {
158
+ const resolved = resolvePikkuFunction(funcName, this.packageName)
136
159
  return await runPikkuFunc<In, Out>(
137
160
  'rpc',
138
161
  funcName,
139
- getPikkuFunctionName(funcName),
162
+ resolved.pikkuFuncId,
140
163
  {
141
164
  auth: this.options.requiresAuth,
142
165
  singletonServices: this.services,
143
166
  data: () => data,
144
167
  wire: updatedWire,
168
+ packageName: resolved.packageName,
145
169
  }
146
170
  )
147
171
  } catch (e) {
@@ -232,17 +256,14 @@ export class ContextAwareRPCService {
232
256
  }
233
257
 
234
258
  try {
235
- return await runPikkuFunc<In, Out>(
236
- 'rpc',
237
- rpcName,
238
- getPikkuFunctionName(rpcName),
239
- {
240
- auth: this.options.requiresAuth,
241
- singletonServices: this.services,
242
- data: () => data,
243
- wire: mergedWire,
244
- }
245
- )
259
+ const resolved = resolvePikkuFunction(rpcName, this.packageName)
260
+ return await runPikkuFunc<In, Out>('rpc', rpcName, resolved.pikkuFuncId, {
261
+ auth: this.options.requiresAuth,
262
+ singletonServices: this.services,
263
+ data: () => data,
264
+ wire: mergedWire,
265
+ packageName: resolved.packageName,
266
+ })
246
267
  } catch (e) {
247
268
  if (e instanceof RPCNotFoundError && this.services.deploymentService) {
248
269
  const session =
@@ -406,14 +427,20 @@ export class PikkuRPCService<
406
427
  sessionService?: SessionService<CoreUserSession>
407
428
  }
408
429
  | undefined,
409
- depth: number = 0
430
+ depth: number = 0,
431
+ packageName: string | null = null
410
432
  ): TypedRPC {
411
433
  const options =
412
434
  typeof requiresAuthOrOptions === 'object' &&
413
435
  requiresAuthOrOptions !== null
414
436
  ? requiresAuthOrOptions
415
437
  : { requiresAuth: requiresAuthOrOptions }
416
- const serviceRPC = new ContextAwareRPCService(services, wire, options)
438
+ const serviceRPC = new ContextAwareRPCService(
439
+ services,
440
+ wire,
441
+ options,
442
+ packageName
443
+ )
417
444
  return {
418
445
  depth,
419
446
  global: false,